When uninstalling a hosted app, delete data for its launch_url's origin, as
long as no other apps are installed on that origin.

(cloned from matt's OCL http://codereview.chromium.org/7747025/)

TBR=mpcomplete
BUG=87258
Review URL: http://codereview.chromium.org/7807002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99288 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 27128efb..e9143d01 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -865,20 +865,16 @@
   // this function.
   std::string extension_id(extension_id_unsafe);
 
-  const Extension* extension = GetInstalledExtension(extension_id);
+  scoped_refptr<const Extension> extension(GetInstalledExtension(extension_id));
 
   // Callers should not send us nonexistent extensions.
   CHECK(extension);
 
-  // Get hold of information we need after unloading, since the extension
-  // pointer will be invalid then.
-  GURL extension_url(extension->url());
-  Extension::Location location(extension->location());
-
   // Policy change which triggers an uninstall will always set
   // |external_uninstall| to true so this is the only way to uninstall
   // managed extensions.
-  if (!Extension::UserMayDisable(location) && !external_uninstall) {
+  if (!Extension::UserMayDisable(extension->location()) &&
+      !external_uninstall) {
     NotificationService::current()->Notify(
         chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED,
         Source<Profile>(profile_),
@@ -917,11 +913,11 @@
   // any of these resources.
   UnloadExtension(extension_id, extension_misc::UNLOAD_REASON_UNINSTALL);
 
-  extension_prefs_->OnExtensionUninstalled(extension_id, location,
+  extension_prefs_->OnExtensionUninstalled(extension_id, extension->location(),
                                            external_uninstall);
 
   // Tell the backend to start deleting installed extensions on the file thread.
-  if (Extension::LOAD != location) {
+  if (Extension::LOAD != extension->location()) {
     if (!BrowserThread::PostTask(
             BrowserThread::FILE, FROM_HERE,
             NewRunnableFunction(
@@ -931,7 +927,20 @@
       NOTREACHED();
   }
 
-  ClearExtensionData(extension_url);
+  GURL launch_web_url_origin(extension->launch_web_url());
+  launch_web_url_origin = launch_web_url_origin.GetOrigin();
+  bool is_storage_isolated =
+    (extension->is_storage_isolated() &&
+    extension->HasAPIPermission(ExtensionAPIPermission::kExperimental));
+
+  if (extension->is_hosted_app() &&
+      !profile_->GetExtensionSpecialStoragePolicy()->
+          IsStorageProtected(launch_web_url_origin)) {
+    ClearExtensionData(extension_id, launch_web_url_origin,
+                       is_storage_isolated);
+  }
+  ClearExtensionData(extension_id, extension->url(), is_storage_isolated);
+
   UntrackTerminatedExtension(extension_id);
 
   // Notify interested parties that we've uninstalled this extension.
@@ -949,9 +958,11 @@
   return true;
 }
 
-void ExtensionService::ClearExtensionData(const GURL& extension_url) {
-  scoped_refptr<ExtensionDataDeleter> deleter(
-      new ExtensionDataDeleter(profile_, extension_url));
+void ExtensionService::ClearExtensionData(const std::string& extension_id,
+                                          const GURL& storage_url,
+                                          bool is_storage_isolated) {
+  scoped_refptr<ExtensionDataDeleter> deleter(new ExtensionDataDeleter(
+      profile_, extension_id, storage_url, is_storage_isolated));
   deleter->StartDeleting();
 }