summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/app_restore_service.cc11
-rw-r--r--apps/app_restore_service.h15
-rw-r--r--apps/app_restore_service_browsertest.cc46
-rw-r--r--chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc42
-rw-r--r--chrome/browser/extensions/api/file_handlers/app_file_handler_util.h34
-rw-r--r--chrome/browser/extensions/api/file_system/file_system_api.cc31
-rw-r--r--chrome/browser/extensions/extension_prefs.cc65
-rw-r--r--chrome/browser/extensions/extension_prefs.h13
-rw-r--r--chrome/test/data/extensions/api_test/file_system/open_background/background.js3
-rw-r--r--chrome/test/data/extensions/api_test/file_system/save_background/background.js3
10 files changed, 237 insertions, 26 deletions
diff --git a/apps/app_restore_service.cc b/apps/app_restore_service.cc
index 554f873..f1b3fd3 100644
--- a/apps/app_restore_service.cc
+++ b/apps/app_restore_service.cc
@@ -5,6 +5,7 @@
#include "apps/app_restore_service.h"
#include "chrome/browser/extensions/api/app_runtime/app_runtime_api.h"
+#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
#include "chrome/browser/extensions/event_router.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_service.h"
@@ -47,9 +48,11 @@ void AppRestoreService::HandleStartup(bool should_restore_apps) {
it != extensions->end(); ++it) {
const Extension* extension = *it;
if (extension_prefs->IsExtensionRunning(extension->id())) {
+ std::vector<SavedFileEntry> file_entries;
+ extension_prefs->GetSavedFileEntries(extension->id(), &file_entries);
RecordAppStop(extension->id());
if (should_restore_apps)
- RestoreApp(*it);
+ RestoreApp(*it, file_entries);
}
}
}
@@ -94,9 +97,13 @@ void AppRestoreService::RecordAppStop(const std::string& extension_id) {
ExtensionPrefs* extension_prefs =
ExtensionSystem::Get(profile_)->extension_service()->extension_prefs();
extension_prefs->SetExtensionRunning(extension_id, false);
+ extension_prefs->ClearSavedFileEntries(extension_id);
}
-void AppRestoreService::RestoreApp(const Extension* extension) {
+void AppRestoreService::RestoreApp(
+ const Extension* extension,
+ const std::vector<SavedFileEntry>& file_entries) {
+ // TODO(koz): Make |file_entries| available to the newly restarted app.
AppEventRouter::DispatchOnRestartedEvent(profile_, extension);
}
diff --git a/apps/app_restore_service.h b/apps/app_restore_service.h
index f919a7a..0217f60 100644
--- a/apps/app_restore_service.h
+++ b/apps/app_restore_service.h
@@ -11,12 +11,19 @@
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
-class Profile;
-
namespace extensions {
class Extension;
+
+namespace app_file_handler_util {
+struct SavedFileEntry;
+}
+
}
+class Profile;
+
+using extensions::app_file_handler_util::SavedFileEntry;
+
namespace apps {
// Tracks what apps need to be restarted when the browser restarts.
@@ -37,7 +44,9 @@ class AppRestoreService : public ProfileKeyedService,
void RecordAppStart(const std::string& extension_id);
void RecordAppStop(const std::string& extension_id);
- void RestoreApp(const extensions::Extension* extension);
+ void RestoreApp(
+ const extensions::Extension* extension,
+ const std::vector<SavedFileEntry>& file_entries);
content::NotificationRegistrar registrar_;
Profile* profile_;
diff --git a/apps/app_restore_service_browsertest.cc b/apps/app_restore_service_browsertest.cc
index 094812d..3eaf3ff 100644
--- a/apps/app_restore_service_browsertest.cc
+++ b/apps/app_restore_service_browsertest.cc
@@ -4,6 +4,8 @@
#include "apps/app_restore_service.h"
#include "apps/app_restore_service_factory.h"
+#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
+#include "chrome/browser/extensions/api/file_system/file_system_api.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
@@ -12,9 +14,12 @@
#include "chrome/common/extensions/extension.h"
#include "content/public/test/test_utils.h"
+using extensions::app_file_handler_util::SavedFileEntry;
using extensions::Extension;
using extensions::ExtensionPrefs;
using extensions::ExtensionSystem;
+using extensions::FileSystemChooseEntryFunction;
+
// TODO(benwells): Move PlatformAppBrowserTest to apps namespace in apps
// component.
using extensions::PlatformAppBrowserTest;
@@ -52,4 +57,45 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, RunningAppsAreRecorded) {
restart_listener.WaitUntilSatisfied();
}
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, FileAccessIsSavedToPrefs) {
+ content::WindowedNotificationObserver extension_suspended(
+ chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
+ content::NotificationService::AllSources());
+
+ base::ScopedTempDir temp_directory;
+ ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
+ base::FilePath temp_file;
+ ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_directory.path(),
+ &temp_file));
+
+ FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
+ &temp_file);
+
+ ExtensionTestMessageListener file_written_listener("fileWritten", false);
+ ExtensionTestMessageListener access_ok_listener(
+ "restartedFileAccessOK", false);
+
+ const Extension* extension =
+ LoadAndLaunchPlatformApp("file_access_saved_to_prefs_test");
+ ASSERT_TRUE(extension);
+ file_written_listener.WaitUntilSatisfied();
+
+ ExtensionService* extension_service =
+ ExtensionSystem::Get(browser()->profile())->extension_service();
+ ExtensionPrefs* extension_prefs = extension_service->extension_prefs();
+
+ // Record the file entries in prefs because when the app gets suspended it
+ // will have them all cleared.
+ std::vector<SavedFileEntry> file_entries;
+ extension_prefs->GetSavedFileEntries(extension->id(), &file_entries);
+ // One for the read-only file entry and one for the writable file entry.
+ ASSERT_EQ(2u, file_entries.size());
+
+ extension_suspended.Wait();
+ file_entries.clear();
+ extension_prefs->GetSavedFileEntries(extension->id(), &file_entries);
+ // File entries should be cleared when the extension is suspended.
+ ASSERT_TRUE(file_entries.empty());
+}
+
} // namespace apps
diff --git a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
index 22d3fa4..d4ff715 100644
--- a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
+++ b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
@@ -4,7 +4,13 @@
#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/extension_system.h"
+#include "content/public/browser/child_process_security_policy.h"
#include "net/base/mime_util.h"
+#include "webkit/fileapi/file_system_types.h"
+#include "webkit/fileapi/isolated_context.h"
namespace extensions {
@@ -82,6 +88,42 @@ bool FileHandlerCanHandleFileWithMimeType(
return false;
}
+GrantedFileEntry CreateFileEntry(
+ Profile* profile,
+ const std::string& extension_id,
+ int renderer_id,
+ const base::FilePath& path,
+ bool writable) {
+ GrantedFileEntry result;
+ fileapi::IsolatedContext* isolated_context =
+ fileapi::IsolatedContext::GetInstance();
+ DCHECK(isolated_context);
+
+ result.filesystem_id = isolated_context->RegisterFileSystemForPath(
+ fileapi::kFileSystemTypeNativeLocal, path, &result.registered_name);
+
+ content::ChildProcessSecurityPolicy* policy =
+ content::ChildProcessSecurityPolicy::GetInstance();
+ policy->GrantReadFileSystem(renderer_id, result.filesystem_id);
+ if (writable)
+ policy->GrantWriteFileSystem(renderer_id, result.filesystem_id);
+
+ result.id = result.filesystem_id + ":" + result.registered_name;
+
+ // We only need file level access for reading FileEntries. Saving FileEntries
+ // just needs the file system to have read/write access, which is granted
+ // above if required.
+ if (!policy->CanReadFile(renderer_id, path))
+ policy->GrantReadFile(renderer_id, path);
+
+ ExtensionPrefs* prefs = extensions::ExtensionSystem::Get(profile)->
+ extension_service()->extension_prefs();
+ // Save this file entry in the prefs.
+ prefs->AddSavedFileEntry(extension_id, result.id, path, writable);
+
+ return result;
+}
+
} // namespace app_file_handler_util
} // namespace extensions
diff --git a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h
index 5bbb90af..a73a0c7 100644
--- a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h
+++ b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h
@@ -12,6 +12,8 @@
#include "chrome/common/extensions/api/file_handlers/file_handlers_parser.h"
#include "chrome/common/extensions/extension.h"
+class Profile;
+
namespace extensions {
// TODO(benwells): move this to platform_apps namespace.
@@ -34,6 +36,38 @@ FindFileHandlersForMimeTypes(const Extension& extension,
bool FileHandlerCanHandleFileWithMimeType(const FileHandlerInfo& handler,
const std::string& mime_type);
+// Represents a file entry that a user has given an extension permission to
+// access. Intended to be persisted to disk (in the Preferences file), so should
+// remain serializable.
+struct SavedFileEntry {
+ SavedFileEntry(const std::string& id,
+ const base::FilePath& path,
+ bool writable)
+ : id(id),
+ path(path),
+ writable(writable) {}
+
+ std::string id;
+ base::FilePath path;
+ bool writable;
+};
+
+// Refers to a file entry that a renderer has been given access to.
+struct GrantedFileEntry {
+ std::string id;
+ std::string filesystem_id;
+ std::string registered_name;
+};
+
+// Creates a new file entry and allows |renderer_id| to access |path|. This
+// registers a new file system for |path|.
+GrantedFileEntry CreateFileEntry(
+ Profile* profile,
+ const std::string& extension_id,
+ int renderer_id,
+ const base::FilePath& path,
+ bool writable);
+
} // namespace app_file_handler_util
} // namespace extensions
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/file_system_api.cc
index 42d51c3..0fc50c1 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_api.cc
@@ -12,6 +12,7 @@
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
#include "chrome/browser/extensions/shell_window_registry.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/ui/chrome_select_file_policy.h"
@@ -40,7 +41,8 @@ using fileapi::IsolatedContext;
const char kInvalidParameters[] = "Invalid parameters";
const char kSecurityError[] = "Security error";
-const char kInvalidCallingPage[] = "Invalid calling page";
+const char kInvalidCallingPage[] = "Invalid calling page. This function can't "
+ "be called from a background page.";
const char kUserCancelled[] = "User cancelled";
const char kWritableFileError[] = "Invalid file for writing";
const char kRequiresFileSystemWriteError[] =
@@ -300,27 +302,18 @@ void FileSystemEntryFunction::RegisterFileSystemAndSendResponse(
fileapi::IsolatedContext::GetInstance();
DCHECK(isolated_context);
- std::string registered_name;
- std::string filesystem_id = isolated_context->RegisterFileSystemForPath(
- fileapi::kFileSystemTypeNativeLocal, path, &registered_name);
-
- content::ChildProcessSecurityPolicy* policy =
- content::ChildProcessSecurityPolicy::GetInstance();
- int renderer_id = render_view_host_->GetProcess()->GetID();
- policy->GrantReadFileSystem(renderer_id, filesystem_id);
- if (entry_type == WRITABLE)
- policy->GrantWriteFileSystem(renderer_id, filesystem_id);
-
- // We only need file level access for reading FileEntries. Saving FileEntries
- // just needs the file system to have read/write access, which is granted
- // above if required.
- if (!policy->CanReadFile(renderer_id, path))
- policy->GrantReadFile(renderer_id, path);
+ bool writable = entry_type == WRITABLE;
+ extensions::app_file_handler_util::GrantedFileEntry file_entry =
+ extensions::app_file_handler_util::CreateFileEntry(profile(),
+ GetExtension()->id(), render_view_host_->GetProcess()->GetID(), path,
+ writable);
DictionaryValue* dict = new DictionaryValue();
SetResult(dict);
- dict->SetString("fileSystemId", filesystem_id);
- dict->SetString("baseName", registered_name);
+ dict->SetString("fileSystemId", file_entry.filesystem_id);
+ dict->SetString("baseName", file_entry.registered_name);
+ dict->SetString("id", file_entry.id);
+
SendResponse(true);
}
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 03592a0..df2d71e 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -12,6 +12,7 @@
#include "base/utf_string_conversions.h"
#include "base/version.h"
#include "chrome/browser/extensions/admin_policy.h"
+#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
#include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
#include "chrome/browser/extensions/extension_pref_store.h"
#include "chrome/browser/extensions/extension_sorting.h"
@@ -41,6 +42,15 @@ namespace {
// Additional preferences keys
+// The file entries that an extension had permission to access.
+const char kFileEntries[] = "file_entries";
+
+// The path to a file entry that an extension had permission to access.
+const char kFileEntryPath[] = "path";
+
+// Whether or not an extension had write access to a file entry.
+const char kFileEntryWritable[] = "writable";
+
// Whether this extension was running when chrome last shutdown.
const char kPrefRunning[] = "running";
@@ -1132,6 +1142,61 @@ bool ExtensionPrefs::IsExtensionRunning(const std::string& extension_id) {
return running;
}
+void ExtensionPrefs::AddSavedFileEntry(
+ const std::string& extension_id,
+ const std::string& file_entry_id,
+ const base::FilePath& file_path,
+ bool writable) {
+ ScopedExtensionPrefUpdate update(prefs_, extension_id);
+ DictionaryValue* extension_dict = update.Get();
+ DictionaryValue* file_entries = NULL;
+ if (!extension_dict->GetDictionary(kFileEntries, &file_entries)) {
+ file_entries = new DictionaryValue();
+ extension_dict->SetWithoutPathExpansion(kFileEntries, file_entries);
+ }
+ // Once a file's permissions are set they can't be changed.
+ DictionaryValue* file_entry_dict = NULL;
+ if (file_entries->GetDictionary(file_entry_id, &file_entry_dict))
+ return;
+
+ file_entry_dict = new DictionaryValue();
+ file_entry_dict->SetString(kFileEntryPath, file_path.value());
+ file_entry_dict->SetBoolean(kFileEntryWritable, writable);
+ file_entries->SetWithoutPathExpansion(file_entry_id, file_entry_dict);
+}
+
+void ExtensionPrefs::ClearSavedFileEntries(
+ const std::string& extension_id) {
+ ScopedExtensionPrefUpdate update(prefs_, extension_id);
+ DictionaryValue* extension_dict = update.Get();
+ extension_dict->Remove(kFileEntries, NULL);
+}
+
+void ExtensionPrefs::GetSavedFileEntries(
+ const std::string& extension_id,
+ std::vector<app_file_handler_util::SavedFileEntry>* out) {
+ const DictionaryValue* prefs = GetExtensionPref(extension_id);
+ const DictionaryValue* file_entries = NULL;
+ if (!prefs->GetDictionary(kFileEntries, &file_entries))
+ return;
+ for (DictionaryValue::key_iterator it = file_entries->begin_keys();
+ it != file_entries->end_keys(); ++it) {
+ std::string id = *it;
+ const DictionaryValue* file_entry = NULL;
+ if (!file_entries->GetDictionaryWithoutPathExpansion(id, &file_entry))
+ continue;
+ base::FilePath::StringType path_string;
+ if (!file_entry->GetString(kFileEntryPath, &path_string))
+ continue;
+ bool writable = false;
+ if (!file_entry->GetBoolean(kFileEntryWritable, &writable))
+ continue;
+ base::FilePath file_path(path_string);
+ out->push_back(app_file_handler_util::SavedFileEntry(
+ id, file_path, writable));
+ }
+}
+
ExtensionOmniboxSuggestion
ExtensionPrefs::GetOmniboxDefaultSuggestion(const std::string& extension_id) {
ExtensionOmniboxSuggestion suggestion;
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index 1c32070..9334d10 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -31,6 +31,10 @@ class ExtensionPrefsUninstallExtension;
class URLPatternSet;
struct ExtensionOmniboxSuggestion;
+namespace app_file_handler_util {
+struct SavedFileEntry;
+}
+
// Class for managing global and per-extension preferences.
//
// This class distinguishes the following kinds of preferences:
@@ -322,6 +326,15 @@ class ExtensionPrefs : public ContentSettingsStore::Observer,
// restart apps across browser restarts.
bool IsExtensionRunning(const std::string& extension_id);
+ void AddSavedFileEntry(const std::string& extension_id,
+ const std::string& id,
+ const base::FilePath& file_path,
+ bool writable);
+ void ClearSavedFileEntries(const std::string& extension_id);
+ void GetSavedFileEntries(
+ const std::string& extension_id,
+ std::vector<app_file_handler_util::SavedFileEntry>* out);
+
// Controls the omnibox default suggestion as set by the extension.
ExtensionOmniboxSuggestion GetOmniboxDefaultSuggestion(
const std::string& extension_id);
diff --git a/chrome/test/data/extensions/api_test/file_system/open_background/background.js b/chrome/test/data/extensions/api_test/file_system/open_background/background.js
index 54a5f36..f742d14 100644
--- a/chrome/test/data/extensions/api_test/file_system/open_background/background.js
+++ b/chrome/test/data/extensions/api_test/file_system/open_background/background.js
@@ -5,6 +5,7 @@
chrome.test.runTests([
function openFile() {
chrome.fileSystem.chooseEntry(chrome.test.callbackFail(
- 'Invalid calling page', function(entry) {}));
+ "Invalid calling page. This function can't be called from a " +
+ "background page.", function(entry) {}));
}
]);
diff --git a/chrome/test/data/extensions/api_test/file_system/save_background/background.js b/chrome/test/data/extensions/api_test/file_system/save_background/background.js
index c1eaa22..9b6f2a0 100644
--- a/chrome/test/data/extensions/api_test/file_system/save_background/background.js
+++ b/chrome/test/data/extensions/api_test/file_system/save_background/background.js
@@ -5,6 +5,7 @@
chrome.test.runTests([
function openFile() {
chrome.fileSystem.chooseEntry({type: 'saveFile'}, chrome.test.callbackFail(
- 'Invalid calling page', function(entry) {}));
+ "Invalid calling page. This function can't be called from a " +
+ "background page.", function(entry) {}));
}
]);