15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/push_messaging/push_messaging_api.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/lazy_instance.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/token_cache/token_cache_service.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/token_cache/token_cache_service_factory.h"
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/signin/signin_manager_factory.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/api/push_messaging.h"
230de6073388f4e2780db8536178b129cd8f6ab386Torne (Richard Coles)#include "components/invalidation/invalidation_service.h"
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/invalidation/profile_invalidation_provider.h"
25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/signin/core/browser/profile_oauth2_token_service.h"
26e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "components/signin/core/browser/signin_manager.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/event_router.h"
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/browser/extension_registry.h"
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "extensions/browser/extension_registry_factory.h"
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system_provider.h"
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extensions_browser_client.h"
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "extensions/common/permissions/api_permission.h"
3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/permissions/permissions_data.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "google_apis/gaia/identity_provider.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace extensions {
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kChannelIdSeparator[] = "/";
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kUserNotSignedIn[] = "The user is not signed in.";
467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst char kUserAccessTokenFailure[] =
477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    "Cannot obtain access token for the user.";
48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochconst char kAPINotAvailableForUser[] =
49c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    "The API is not available for this user.";
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kObfuscatedGaiaIdTimeoutInDays = 30;
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char kDeprecationMessage[] =
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    "The chrome.pushMessaging API is deprecated. Use chrome.gcm API instead.";
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace glue = api::push_messaging;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)PushMessagingEventRouter::PushMessagingEventRouter(
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    content::BrowserContext* context)
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : browser_context_(context) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PushMessagingEventRouter::~PushMessagingEventRouter() {}
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingEventRouter::TriggerMessageForTest(
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& extension_id,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int subchannel,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& payload) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnMessage(extension_id, subchannel, payload);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingEventRouter::OnMessage(const std::string& extension_id,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         int subchannel,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const std::string& payload) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glue::Message message;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message.subchannel_id = subchannel;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message.payload = payload;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(2) << "PushMessagingEventRouter::OnMessage"
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << " payload = '" << payload
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << "' subchannel = '" << subchannel
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           << "' extension = '" << extension_id << "'";
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::ListValue> args(glue::OnMessage::Create(message));
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<Event> event(new Event(glue::OnMessage::kEventName, args.Pass()));
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  event->restrict_to_browser_context = browser_context_;
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  EventRouter::Get(browser_context_)
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ->DispatchEventToExtension(extension_id, event.Pass());
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GetChannelId class functions
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PushMessagingGetChannelIdFunction::PushMessagingGetChannelIdFunction()
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : OAuth2TokenService::Consumer("push_messaging"),
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      interactive_(false) {}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PushMessagingGetChannelIdFunction::~PushMessagingGetChannelIdFunction() {}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool PushMessagingGetChannelIdFunction::RunAsync() {
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Issue a deprecation message.
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_WARNING, kDeprecationMessage);
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fetch the function arguments.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<glue::GetChannelId::Params> params(
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      glue::GetChannelId::Params::Create(*args_));
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EXTENSION_FUNCTION_VALIDATE(params.get());
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params && params->interactive) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    interactive_ = *params->interactive;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Balanced in ReportResult()
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddRef();
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  invalidation::ProfileInvalidationProvider* invalidation_provider =
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      invalidation::ProfileInvalidationProviderFactory::GetForProfile(
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          GetProfile());
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!invalidation_provider) {
118c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    error_ = kAPINotAvailableForUser;
119c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    ReportResult(std::string(), error_);
120c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return false;
121c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
122c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  IdentityProvider* identity_provider =
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      invalidation_provider->GetInvalidationService()->GetIdentityProvider();
1250529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!identity_provider->GetTokenService()->RefreshTokenIsAvailable(
1260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          identity_provider->GetActiveAccountId())) {
1270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (interactive_ && identity_provider->RequestLogin()) {
1280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      identity_provider->AddActiveAccountRefreshTokenObserver(this);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error_ = kUserNotSignedIn;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ReportResult(std::string(), error_);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DVLOG(2) << "Logged in profile name: " << GetProfile()->GetProfileName();
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  StartAccessTokenFetch();
1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PushMessagingGetChannelIdFunction::StartAccessTokenFetch() {
144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  invalidation::ProfileInvalidationProvider* invalidation_provider =
145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      invalidation::ProfileInvalidationProviderFactory::GetForProfile(
146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          GetProfile());
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  CHECK(invalidation_provider);
1480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  IdentityProvider* identity_provider =
149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      invalidation_provider->GetInvalidationService()->GetIdentityProvider();
150c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::vector<std::string> scope_vector = ObfuscatedGaiaIdFetcher::GetScopes();
1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  OAuth2TokenService::ScopeSet scopes(scope_vector.begin(), scope_vector.end());
15323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  fetcher_access_token_request_ =
1540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      identity_provider->GetTokenService()->StartRequest(
1550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          identity_provider->GetActiveAccountId(), scopes, this);
1567dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PushMessagingGetChannelIdFunction::OnRefreshTokenAvailable(
1597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& account_id) {
160f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  invalidation::ProfileInvalidationProvider* invalidation_provider =
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      invalidation::ProfileInvalidationProviderFactory::GetForProfile(
162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          GetProfile());
163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  CHECK(invalidation_provider);
164f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  invalidation_provider->GetInvalidationService()->GetIdentityProvider()->
1650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      RemoveActiveAccountRefreshTokenObserver(this);
1661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DVLOG(2) << "Newly logged in: " << GetProfile()->GetProfileName();
1677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  StartAccessTokenFetch();
1687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PushMessagingGetChannelIdFunction::OnGetTokenSuccess(
1717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const OAuth2TokenService::Request* request,
1727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& access_token,
1737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const base::Time& expiration_time) {
1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_EQ(fetcher_access_token_request_.get(), request);
1757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  fetcher_access_token_request_.reset();
1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  StartGaiaIdFetch(access_token);
1787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PushMessagingGetChannelIdFunction::OnGetTokenFailure(
1817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const OAuth2TokenService::Request* request,
1827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const GoogleServiceAuthError& error) {
1837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_EQ(fetcher_access_token_request_.get(), request);
1847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  fetcher_access_token_request_.reset();
1857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // TODO(fgorski): We are currently ignoring the error passed in upon failure.
1877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // It should be revisited when we are working on improving general error
1887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // handling for the identity related code.
1893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DVLOG(1) << "Cannot obtain access token for this user "
1903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)           << error.error_message() << " " << error.state();
1917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  error_ = kUserAccessTokenFailure;
1927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ReportResult(std::string(), error_);
193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid PushMessagingGetChannelIdFunction::StartGaiaIdFetch(
1967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const std::string& access_token) {
197c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Start the async fetch of the Gaia Id.
198effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
1991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  net::URLRequestContextGetter* context = GetProfile()->GetRequestContext();
2007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  fetcher_.reset(new ObfuscatedGaiaIdFetcher(context, this, access_token));
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Get the token cache and see if we have already cached a Gaia Id.
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TokenCacheService* token_cache =
2041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      TokenCacheServiceFactory::GetForProfile(GetProfile());
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Check the cache, if we already have a Gaia ID, use it instead of
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // fetching the ID over the network.
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const std::string& gaia_id =
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      token_cache->RetrieveToken(GaiaConstants::kObfuscatedGaiaId);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gaia_id.empty()) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ReportResult(gaia_id, std::string());
2127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetcher_->Start();
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingGetChannelIdFunction::ReportResult(
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& gaia_id, const std::string& error_string) {
220effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK_CURRENTLY_ON(BrowserThread::UI);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BuildAndSendResult(gaia_id, error_string);
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cache the obfuscated ID locally. It never changes for this user,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and if we call the web API too often, we get errors due to rate limiting.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gaia_id.empty()) {
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::TimeDelta timeout =
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeDelta::FromDays(kObfuscatedGaiaIdTimeoutInDays);
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    TokenCacheService* token_cache =
2301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        TokenCacheServiceFactory::GetForProfile(GetProfile());
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    token_cache->StoreToken(GaiaConstants::kObfuscatedGaiaId, gaia_id,
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            timeout);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Balanced in RunAsync.
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingGetChannelIdFunction::BuildAndSendResult(
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& gaia_id, const std::string& error_message) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string channel_id;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gaia_id.empty()) {
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    channel_id = gaia_id;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    channel_id += kChannelIdSeparator;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    channel_id += extension_id();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(petewil): It may be a good idea to further
249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // obfuscate the channel ID to prevent the user's obfuscated Gaia Id
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from being readily obtained.  Security review will tell us if we need to.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a ChannelId results object and set the fields.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  glue::ChannelIdResult result;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result.channel_id = channel_id;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetError(error_message);
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results_ = glue::GetChannelId::Results::Create(result);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = error_message.empty() && !gaia_id.empty();
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendResponse(success);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingGetChannelIdFunction::OnObfuscatedGaiaIdFetchSuccess(
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& gaia_id) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReportResult(gaia_id, std::string());
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PushMessagingGetChannelIdFunction::OnObfuscatedGaiaIdFetchFailure(
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const GoogleServiceAuthError& error) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string error_text = error.error_message();
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the error message is blank, see if we can set it from the state.
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (error_text.empty() &&
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (0 != error.state())) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    error_text = base::IntToString(error.state());
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DVLOG(1) << "GetChannelId status: '" << error_text << "'";
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If we had bad credentials, try the logon again.
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  switch (error.state()) {
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case GoogleServiceAuthError::ACCOUNT_DELETED:
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    case GoogleServiceAuthError::ACCOUNT_DISABLED: {
283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      invalidation::ProfileInvalidationProvider* invalidation_provider =
284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          invalidation::ProfileInvalidationProviderFactory::GetForProfile(
285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              GetProfile());
286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      CHECK(invalidation_provider);
287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (!interactive_ || !invalidation_provider->GetInvalidationService()->
288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)              GetIdentityProvider()->RequestLogin()) {
289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        ReportResult(std::string(), error_text);
290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    default:
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Return error to caller.
295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ReportResult(std::string(), error_text);
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      return;
297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PushMessagingAPI::PushMessagingAPI(content::BrowserContext* context)
301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : extension_registry_observer_(this), browser_context_(context) {
302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PushMessagingAPI::~PushMessagingAPI() {
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PushMessagingAPI* PushMessagingAPI::Get(content::BrowserContext* context) {
310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return BrowserContextKeyedAPIFactory<PushMessagingAPI>::Get(context);
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PushMessagingAPI::Shutdown() {
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event_router_.reset();
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handler_.reset();
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
318a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static base::LazyInstance<BrowserContextKeyedAPIFactory<PushMessagingAPI> >
319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    g_factory = LAZY_INSTANCE_INITIALIZER;
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
322a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<PushMessagingAPI>*
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PushMessagingAPI::GetFactoryInstance() {
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return g_factory.Pointer();
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool PushMessagingAPI::InitEventRouterAndHandler() {
328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  invalidation::ProfileInvalidationProvider* invalidation_provider =
329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      invalidation::ProfileInvalidationProviderFactory::GetForProfile(
330f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          Profile::FromBrowserContext(browser_context_));
331f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!invalidation_provider)
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!event_router_)
335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    event_router_.reset(new PushMessagingEventRouter(browser_context_));
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!handler_) {
337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    handler_.reset(new PushMessagingInvalidationHandler(
338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        invalidation_provider->GetInvalidationService(),
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        event_router_.get()));
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return true;
343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
344cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
345cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PushMessagingAPI::OnExtensionLoaded(
346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    content::BrowserContext* browser_context,
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const Extension* extension) {
348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!InitEventRouterAndHandler())
349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
35146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (extension->permissions_data()->HasAPIPermission(
35246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          APIPermission::kPushMessaging)) {
353cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    handler_->RegisterExtension(extension->id());
354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
355cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PushMessagingAPI::OnExtensionUnloaded(
358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    content::BrowserContext* browser_context,
359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const Extension* extension,
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    UnloadedExtensionInfo::Reason reason) {
361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!InitEventRouterAndHandler())
362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
36446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (extension->permissions_data()->HasAPIPermission(
36546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          APIPermission::kPushMessaging)) {
366cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    handler_->UnregisterExtension(extension->id());
367cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
370f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void PushMessagingAPI::OnExtensionWillBeInstalled(
371f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    content::BrowserContext* browser_context,
372f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const Extension* extension,
373f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    bool is_update,
374f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    bool from_ephemeral,
375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& old_name) {
376f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (InitEventRouterAndHandler() &&
377f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      extension->permissions_data()->HasAPIPermission(
37846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          APIPermission::kPushMessaging)) {
379cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    handler_->SuppressInitialInvalidationsForExtension(extension->id());
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void PushMessagingAPI::SetMapperForTest(
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<PushMessagingInvalidationMapper> mapper) {
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handler_ = mapper.Pass();
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template <>
389a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void
390a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<PushMessagingAPI>::DeclareFactoryDependencies() {
391f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DependsOn(ExtensionRegistryFactory::GetInstance());
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
393f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DependsOn(invalidation::ProfileInvalidationProviderFactory::GetInstance());
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
397