Don't allow OAuth2MintTokenFlow to outlive profile.

BUG=150911

Review URL: https://codereview.chromium.org/10966009

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@159502 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/permissions_updater.cc b/chrome/browser/extensions/permissions_updater.cc
index 06e921d..2a61b992 100644
--- a/chrome/browser/extensions/permissions_updater.cc
+++ b/chrome/browser/extensions/permissions_updater.cc
@@ -18,6 +18,8 @@
 #include "chrome/common/extensions/api/permissions.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_messages.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_process_host.h"
 #include "google_apis/gaia/oauth2_mint_token_flow.h"
@@ -33,7 +35,59 @@
 const char kOnAdded[] = "permissions.onAdded";
 const char kOnRemoved[] = "permissions.onRemoved";
 
-}
+// An object to link the lifetime of an OAuth2MintTokenFlow to a Profile.
+// The flow should not outlive the profile because the request context will
+// become invalid.
+class OAuth2GrantRecorder : public OAuth2MintTokenFlow::Delegate,
+                            public content::NotificationObserver {
+ public:
+  OAuth2GrantRecorder(Profile* profile, const Extension* extension)
+    : ALLOW_THIS_IN_INITIALIZER_LIST(flow_(
+          profile->GetRequestContext(),
+          this,
+          OAuth2MintTokenFlow::Parameters(
+              TokenServiceFactory::GetForProfile(profile)->
+                  GetOAuth2LoginRefreshToken(),
+              extension->id(),
+              extension->oauth2_info().client_id,
+              extension->oauth2_info().scopes,
+              OAuth2MintTokenFlow::MODE_RECORD_GRANT))) {
+    notification_registrar_.Add(this,
+                                chrome::NOTIFICATION_PROFILE_DESTROYED,
+                                content::Source<Profile>(profile));
+
+    flow_.Start();
+  }
+
+  // content::NotificationObserver:
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) OVERRIDE {
+    DCHECK_EQ(type, chrome::NOTIFICATION_PROFILE_DESTROYED);
+    delete this;
+  }
+
+  // OAuth2MintTokenFlow::Delegate:
+  virtual void OnMintTokenSuccess(const std::string& access_token) OVERRIDE {
+    delete this;
+  }
+  virtual void OnIssueAdviceSuccess(
+      const IssueAdviceInfo& issue_advice) OVERRIDE {
+    delete this;
+  }
+  virtual void OnMintTokenFailure(
+      const GoogleServiceAuthError& error) OVERRIDE {
+    delete this;
+  }
+
+ private:
+  virtual ~OAuth2GrantRecorder() {}
+
+  OAuth2MintTokenFlow flow_;
+  content::NotificationRegistrar notification_registrar_;
+};
+
+}  // namespace
 
 PermissionsUpdater::PermissionsUpdater(Profile* profile)
     : profile_(profile) {}
@@ -85,7 +139,7 @@
     return;
 
   if (record_oauth2_grant)
-    RecordOAuth2Grant(extension);
+    new OAuth2GrantRecorder(profile_, extension);
 
   GetExtensionPrefs()->AddGrantedPermissions(extension->id(),
                                              extension->GetActivePermissions());
@@ -97,19 +151,6 @@
   extension->SetActivePermissions(permissions);
 }
 
-void PermissionsUpdater::RecordOAuth2Grant(const Extension* extension) {
-  TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
-  OAuth2MintTokenFlow* flow = new OAuth2MintTokenFlow(
-      profile_->GetRequestContext(), NULL, OAuth2MintTokenFlow::Parameters(
-          token_service->GetOAuth2LoginRefreshToken(),
-          extension->id(),
-          extension->oauth2_info().client_id,
-          extension->oauth2_info().scopes,
-          OAuth2MintTokenFlow::MODE_RECORD_GRANT));
-  // |flow| will delete itself.
-  flow->FireAndForget();
-}
-
 void PermissionsUpdater::DispatchEvent(
     const std::string& extension_id,
     const char* event_name,