summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkoz@chromium.org <koz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-13 13:14:57 +0000
committerkoz@chromium.org <koz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-13 13:14:57 +0000
commitfc2a40fab7f0d6347eba9ce7757532d5b47b977d (patch)
tree3cd2457629926cffd25702e2b91dbdc9e3f5ef90
parentb790fd02a239844bfbf29ebaa204ee40ce0eaea2 (diff)
downloadchromium_src-fc2a40fab7f0d6347eba9ce7757532d5b47b977d.zip
chromium_src-fc2a40fab7f0d6347eba9ce7757532d5b47b977d.tar.gz
chromium_src-fc2a40fab7f0d6347eba9ce7757532d5b47b977d.tar.bz2
Give an app the file entries it had back on restart.
BUG=165832 Review URL: https://chromiumcodereview.appspot.com/12391006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187846 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--apps/app_restore_service.cc6
-rw-r--r--apps/app_restore_service_browsertest.cc48
-rw-r--r--chrome/browser/extensions/api/app_runtime/app_runtime_api.cc21
-rw-r--r--chrome/browser/extensions/api/app_runtime/app_runtime_api.h10
-rw-r--r--chrome/browser/extensions/extension_service.cc22
-rw-r--r--chrome/browser/extensions/extension_service.h12
-rw-r--r--chrome/browser/extensions/platform_app_launcher.cc79
-rw-r--r--chrome/browser/extensions/platform_app_launcher.h11
-rw-r--r--chrome/renderer/resources/extensions/app_runtime_custom_bindings.js32
-rw-r--r--chrome/renderer/resources/extensions/file_system_custom_bindings.js3
-rw-r--r--chrome/test/data/extensions/platform_apps/file_access_restored_test/index.html1
-rw-r--r--chrome/test/data/extensions/platform_apps/file_access_restored_test/manifest.json11
-rw-r--r--chrome/test/data/extensions/platform_apps/file_access_restored_test/test.js74
13 files changed, 318 insertions, 12 deletions
diff --git a/apps/app_restore_service.cc b/apps/app_restore_service.cc
index f1b3fd3..683718a 100644
--- a/apps/app_restore_service.cc
+++ b/apps/app_restore_service.cc
@@ -10,6 +10,7 @@
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
+#include "chrome/browser/extensions/platform_app_launcher.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_set.h"
@@ -103,8 +104,9 @@ void AppRestoreService::RecordAppStop(const std::string& extension_id) {
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);
+ extensions::RestartPlatformAppWithFileEntries(profile_,
+ extension,
+ file_entries);
}
} // namespace apps
diff --git a/apps/app_restore_service_browsertest.cc b/apps/app_restore_service_browsertest.cc
index 3eaf3ff..f17cc64 100644
--- a/apps/app_restore_service_browsertest.cc
+++ b/apps/app_restore_service_browsertest.cc
@@ -98,4 +98,52 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, FileAccessIsSavedToPrefs) {
ASSERT_TRUE(file_entries.empty());
}
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, FileAccessIsRestored) {
+ 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_restored_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);
+ extension_suspended.Wait();
+
+ // Simulate a restart by populating the preferences as if the browser didn't
+ // get time to clean itself up.
+ extension_prefs->SetExtensionRunning(extension->id(), true);
+ for (std::vector<SavedFileEntry>::const_iterator it = file_entries.begin();
+ it != file_entries.end(); ++it) {
+ extension_prefs->AddSavedFileEntry(
+ extension->id(), it->id, it->path, it->writable);
+ }
+
+ apps::AppRestoreServiceFactory::GetForProfile(browser()->profile())->
+ HandleStartup(true);
+
+ access_ok_listener.WaitUntilSatisfied();
+}
+
} // namespace apps
diff --git a/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc b/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
index ff70376..10e29f57 100644
--- a/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
+++ b/chrome/browser/extensions/api/app_runtime/app_runtime_api.cc
@@ -9,6 +9,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.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_system.h"
#include "chrome/browser/profiles/profile.h"
@@ -51,10 +52,28 @@ void AppEventRouter::DispatchOnLaunchedEvent(
DispatchOnLaunchedEventImpl(extension->id(), arguments.Pass(), profile);
}
+DictionaryValue* DictionaryFromSavedFileEntry(
+ const app_file_handler_util::GrantedFileEntry& file_entry) {
+ DictionaryValue* result = new DictionaryValue();
+ result->SetString("id", file_entry.id);
+ result->SetString("fileSystemId", file_entry.filesystem_id);
+ result->SetString("baseName", file_entry.registered_name);
+ return result;
+}
+
// static.
void AppEventRouter::DispatchOnRestartedEvent(
- Profile* profile, const Extension* extension) {
+ Profile* profile,
+ const Extension* extension,
+ const std::vector<app_file_handler_util::GrantedFileEntry>& file_entries) {
+ ListValue* file_entries_list = new ListValue();
+ for (std::vector<extensions::app_file_handler_util::GrantedFileEntry>
+ ::const_iterator it = file_entries.begin(); it != file_entries.end();
+ ++it) {
+ file_entries_list->Append(DictionaryFromSavedFileEntry(*it));
+ }
scoped_ptr<ListValue> arguments(new ListValue());
+ arguments->Append(file_entries_list);
scoped_ptr<Event> event(new Event(kOnRestartedEvent, arguments.Pass()));
event->restrict_to_profile = profile;
extensions::ExtensionSystem::Get(profile)->event_router()->
diff --git a/chrome/browser/extensions/api/app_runtime/app_runtime_api.h b/chrome/browser/extensions/api/app_runtime/app_runtime_api.h
index 84ade63..f9075b4 100644
--- a/chrome/browser/extensions/api/app_runtime/app_runtime_api.h
+++ b/chrome/browser/extensions/api/app_runtime/app_runtime_api.h
@@ -18,14 +18,20 @@ namespace extensions {
class Extension;
+namespace app_file_handler_util {
+struct GrantedFileEntry;
+}
+
class AppEventRouter {
public:
// Dispatches the onLaunched event to the given app, providing no launch
// data.
static void DispatchOnLaunchedEvent(Profile* profile,
const Extension* extension);
- static void DispatchOnRestartedEvent(Profile* profile,
- const Extension* extension);
+ static void DispatchOnRestartedEvent(
+ Profile* profile,
+ const Extension* extension,
+ const std::vector<app_file_handler_util::GrantedFileEntry>& file_entries);
// TODO(benwells): Update this comment, it is out of date.
// Dispatches the onLaunched event to the given app, providing launch data of
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 38df2d4..832218d 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -32,6 +32,7 @@
#include "chrome/browser/extensions/api/app_runtime/app_runtime_api.h"
#include "chrome/browser/extensions/api/declarative/rules_registry_service.h"
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
+#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
#include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
#include "chrome/browser/extensions/api/runtime/runtime_api.h"
#include "chrome/browser/extensions/api/storage/settings_frontend.h"
@@ -743,6 +744,11 @@ void ExtensionService::ReloadExtensionWithEvents(
}
on_load_events_[extension_id] = events;
+ if (events & EVENT_RESTARTED) {
+ extension_prefs_->GetSavedFileEntries(
+ extension_id, &on_restart_file_entries_[extension_id]);
+ }
+
if (delayed_updates_for_idle_.Contains(extension_id)) {
FinishDelayedInstallation(extension_id);
@@ -2910,9 +2916,16 @@ void ExtensionService::DoPostLoadTasks(const Extension* extension) {
if (events_to_fire & EVENT_LAUNCHED)
queue->AddPendingTask(profile(), extension->id(),
base::Bind(&ExtensionService::LaunchApplication));
- if (events_to_fire & EVENT_RESTARTED)
+ if (events_to_fire & EVENT_RESTARTED) {
+ SavedFileEntryMap::iterator it =
+ on_restart_file_entries_.find(extension->id());
+ if (it == on_restart_file_entries_.end())
+ NOTREACHED();
queue->AddPendingTask(profile(), extension->id(),
- base::Bind(&ExtensionService::RestartApplication));
+ base::Bind(&ExtensionService::RestartApplication,
+ it->second));
+ on_restart_file_entries_.erase(it);
+ }
}
on_load_events_.erase(it);
@@ -2933,13 +2946,14 @@ void ExtensionService::LaunchApplication(
// static
void ExtensionService::RestartApplication(
+ std::vector<extensions::app_file_handler_util::SavedFileEntry> file_entries,
extensions::ExtensionHost* extension_host) {
if (!extension_host)
return;
#if !defined(OS_ANDROID)
- extensions::AppEventRouter::DispatchOnRestartedEvent(
- extension_host->profile(), extension_host->extension());
+ extensions::RestartPlatformAppWithFileEntries(
+ extension_host->profile(), extension_host->extension(), file_entries);
#endif
}
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 7fb4a13..7a4eaea 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -796,7 +796,10 @@ class ExtensionService
// Dispatches a restart event to the platform app associated with
// |extension_host|.
- static void RestartApplication(extensions::ExtensionHost* extension_host);
+ static void RestartApplication(
+ std::vector<extensions::app_file_handler_util::SavedFileEntry>
+ file_entries,
+ extensions::ExtensionHost* extension_host);
// Helper to inspect an ExtensionHost after it has been loaded.
void InspectExtensionHost(extensions::ExtensionHost* host);
@@ -924,6 +927,13 @@ class ExtensionService
// dispatched to the extension when it is loaded.
std::map<std::string, int> on_load_events_;
+ // Maps extension ids to vectors of saved file entries that the extension
+ // should be given access to on restart.
+ typedef std::map<std::string,
+ std::vector<extensions::app_file_handler_util::SavedFileEntry> >
+ SavedFileEntryMap;
+ SavedFileEntryMap on_restart_file_entries_;
+
content::NotificationRegistrar registrar_;
PrefChangeRegistrar pref_change_registrar_;
diff --git a/chrome/browser/extensions/platform_app_launcher.cc b/chrome/browser/extensions/platform_app_launcher.cc
index 78548d8..0d37609 100644
--- a/chrome/browser/extensions/platform_app_launcher.cc
+++ b/chrome/browser/extensions/platform_app_launcher.cc
@@ -13,8 +13,11 @@
#include "base/utf_string_conversions.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/api/file_system/file_system_api.h"
#include "chrome/browser/extensions/extension_host.h"
+#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/lazy_background_task_queue.h"
#include "chrome/browser/profiles/profile.h"
@@ -33,6 +36,9 @@ using content::BrowserThread;
using extensions::app_file_handler_util::FileHandlerForId;
using extensions::app_file_handler_util::FileHandlerCanHandleFileWithMimeType;
using extensions::app_file_handler_util::FirstFileHandlerForMimeType;
+using extensions::app_file_handler_util::CreateFileEntry;
+using extensions::app_file_handler_util::GrantedFileEntry;
+using extensions::app_file_handler_util::SavedFileEntry;
namespace extensions {
@@ -239,6 +245,70 @@ class PlatformAppPathLauncher
DISALLOW_COPY_AND_ASSIGN(PlatformAppPathLauncher);
};
+class SavedFileEntryLauncher
+ : public base::RefCountedThreadSafe<SavedFileEntryLauncher> {
+ public:
+ SavedFileEntryLauncher(
+ Profile* profile,
+ const Extension* extension,
+ const std::vector<SavedFileEntry>& file_entries)
+ : profile_(profile),
+ extension_(extension),
+ file_entries_(file_entries) {}
+
+ void Launch() {
+ // Access needs to be granted to the file or filesystem for the process
+ // associated with the extension. To do this the ExtensionHost is needed.
+ // This might not be available, or it might be in the process of being
+ // unloaded, in which case the lazy background task queue is used to load
+ // he extension and then call back to us.
+ extensions::LazyBackgroundTaskQueue* queue =
+ ExtensionSystem::Get(profile_)->lazy_background_task_queue();
+ if (queue->ShouldEnqueueTask(profile_, extension_)) {
+ queue->AddPendingTask(profile_, extension_->id(), base::Bind(
+ &SavedFileEntryLauncher::GrantAccessToFilesAndLaunch,
+ this));
+ return;
+ }
+ ExtensionProcessManager* process_manager =
+ ExtensionSystem::Get(profile_)->process_manager();
+ extensions::ExtensionHost* host =
+ process_manager->GetBackgroundHostForExtension(extension_->id());
+ DCHECK(host);
+ GrantAccessToFilesAndLaunch(host);
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<SavedFileEntryLauncher>;
+ ~SavedFileEntryLauncher() {}
+ void GrantAccessToFilesAndLaunch(ExtensionHost* host) {
+ int renderer_id = host->render_process_host()->GetID();
+ std::vector<GrantedFileEntry> granted_file_entries;
+ for (std::vector<SavedFileEntry>::const_iterator it =
+ file_entries_.begin(); it != file_entries_.end(); ++it) {
+ GrantedFileEntry file_entry = CreateFileEntry(
+ profile_, extension_->id(), renderer_id, it->path, it->writable);
+ file_entry.id = it->id;
+ granted_file_entries.push_back(file_entry);
+
+ // Record that we have granted this file permission.
+ ExtensionPrefs* extension_prefs = ExtensionSystem::Get(profile_)->
+ extension_service()->extension_prefs();
+ extension_prefs->AddSavedFileEntry(
+ host->extension()->id(), it->id, it->path, it->writable);
+ }
+ extensions::AppEventRouter::DispatchOnRestartedEvent(
+ profile_, extension_, granted_file_entries);
+ }
+
+ // The profile the app should be run in.
+ Profile* profile_;
+ // The extension providing the app.
+ const Extension* extension_;
+
+ std::vector<SavedFileEntry> file_entries_;
+};
+
} // namespace
void LaunchPlatformApp(Profile* profile,
@@ -275,4 +345,13 @@ void LaunchPlatformAppWithFileHandler(Profile* profile,
launcher->LaunchWithHandler(handler_id);
}
+void RestartPlatformAppWithFileEntries(
+ Profile* profile,
+ const Extension* extension,
+ const std::vector<SavedFileEntry>& file_entries) {
+ scoped_refptr<SavedFileEntryLauncher> launcher = new SavedFileEntryLauncher(
+ profile, extension, file_entries);
+ launcher->Launch();
+}
+
} // namespace extensions
diff --git a/chrome/browser/extensions/platform_app_launcher.h b/chrome/browser/extensions/platform_app_launcher.h
index c301c45..fc7965a 100644
--- a/chrome/browser/extensions/platform_app_launcher.h
+++ b/chrome/browser/extensions/platform_app_launcher.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_LAUNCHER_H_
#include <string>
+#include <vector>
class CommandLine;
class Profile;
@@ -22,6 +23,10 @@ namespace extensions {
class Extension;
+namespace app_file_handler_util {
+struct SavedFileEntry;
+}
+
// Launches the platform app |extension|. Creates appropriate launch data for
// the |command_line| fields present. |extension| and |profile| must not be
// NULL. A NULL |command_line| means there is no launch data. If non-empty,
@@ -44,6 +49,12 @@ void LaunchPlatformAppWithFileHandler(Profile* profile,
const std::string& handler_id,
const base::FilePath& file_path);
+void RestartPlatformAppWithFileEntries(
+ Profile* profile,
+ const Extension* extension,
+ const std::vector<app_file_handler_util::SavedFileEntry>&
+ saved_file_entries);
+
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_LAUNCHER_H_
diff --git a/chrome/renderer/resources/extensions/app_runtime_custom_bindings.js b/chrome/renderer/resources/extensions/app_runtime_custom_bindings.js
index d17d2e5..0f3a0f7 100644
--- a/chrome/renderer/resources/extensions/app_runtime_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/app_runtime_custom_bindings.js
@@ -15,6 +15,38 @@ var appNatives = requireNative('app_runtime');
var DeserializeString = appNatives.DeserializeString;
var SerializeToString = appNatives.SerializeToString;
var CreateBlob = appNatives.CreateBlob;
+var entryIdManager = require('entryIdManager');
+
+chromeHidden.Event.registerArgumentMassager('app.runtime.onRestarted',
+ function(args, dispatch) {
+ // These file entries don't get dispatched, we just use this hook to register
+ // them all with entryIdManager.
+ var fileEntries = args[0];
+
+ var pendingCallbacks = fileEntries.length;
+
+ var dispatchIfNoPendingCallbacks = function() {
+ if (pendingCallbacks == 0)
+ dispatch([]);
+ };
+
+ for (var i = 0; i < fileEntries.length; i++) {
+ var fe = fileEntries[i];
+ var fs = GetIsolatedFileSystem(fe.fileSystemId);
+ (function(fe, fs) {
+ fs.root.getFile(fe.baseName, {}, function(fileEntry) {
+ entryIdManager.registerEntry(fe.id, fileEntry);
+ pendingCallbacks--;
+ dispatchIfNoPendingCallbacks();
+ }, function(err) {
+ console.error('Error getting fileEntry, code: ' + err.code);
+ pendingCallbacks--;
+ dispatchIfNoPendingCallbacks();
+ });
+ })(fe, fs);
+ }
+ dispatchIfNoPendingCallbacks();
+});
chromeHidden.Event.registerArgumentMassager('app.runtime.onLaunched',
function(args, dispatch) {
diff --git a/chrome/renderer/resources/extensions/file_system_custom_bindings.js b/chrome/renderer/resources/extensions/file_system_custom_bindings.js
index 123eabe..acf163a 100644
--- a/chrome/renderer/resources/extensions/file_system_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/file_system_custom_bindings.js
@@ -36,8 +36,7 @@ binding.registerCustomHook(function(bindingsAPI) {
var fileSystemId = response.fileSystemId;
var baseName = response.baseName;
- // TODO(koz): Generate a persistent id in the browser and use it here.
- var id = fileSystemId + ":" + baseName;
+ var id = response.id;
var fs = GetIsolatedFileSystem(fileSystemId);
try {
diff --git a/chrome/test/data/extensions/platform_apps/file_access_restored_test/index.html b/chrome/test/data/extensions/platform_apps/file_access_restored_test/index.html
new file mode 100644
index 0000000..45b983b
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/file_access_restored_test/index.html
@@ -0,0 +1 @@
+hi
diff --git a/chrome/test/data/extensions/platform_apps/file_access_restored_test/manifest.json b/chrome/test/data/extensions/platform_apps/file_access_restored_test/manifest.json
new file mode 100644
index 0000000..4f6d3e3
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/file_access_restored_test/manifest.json
@@ -0,0 +1,11 @@
+{
+ "name": "Files Preserved Test",
+ "version": "1",
+ "manifest_version": 2,
+ "app": {
+ "background": {
+ "scripts": ["test.js"]
+ }
+ },
+ "permissions": ["fileSystem", "fileSystem.write", "storage"]
+}
diff --git a/chrome/test/data/extensions/platform_apps/file_access_restored_test/test.js b/chrome/test/data/extensions/platform_apps/file_access_restored_test/test.js
new file mode 100644
index 0000000..07ebb0b
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/file_access_restored_test/test.js
@@ -0,0 +1,74 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var expectedText = 'def';
+
+function truncateAndWriteToFile(writableEntry, callback) {
+ writableEntry.createWriter(function(fileWriter) {
+ fileWriter.onerror = function(e) {
+ console.error("Couldn't write file: " + e.toString());
+ };
+ fileWriter.onwriteend = function(e) {
+ fileWriter.onwriteend = function(e) {
+ callback();
+ };
+ var blob = new Blob([expectedText], {type: 'text/plain'});
+ fileWriter.write(blob);
+ };
+ fileWriter.truncate(0);
+ });
+}
+
+chrome.app.runtime.onLaunched.addListener(function() {
+ chrome.app.window.create('index.html', {width: 100, height: 100},
+ function(win) {
+ var fs = win.contentWindow.chrome.fileSystem;
+ fs.chooseEntry({type: 'openFile'}, function(entry) {
+ fs.getWritableEntry(entry, function(writableEntry) {
+ var id = fs.getEntryId(entry);
+ chrome.storage.local.set({id:id}, function() {
+ truncateAndWriteToFile(writableEntry, function() {
+ chrome.test.sendMessage('fileWritten');
+ win.close();
+ });
+ });
+ });
+ });
+ });
+});
+
+chrome.app.runtime.onRestarted.addListener(function() {
+ chrome.storage.local.get(null, function(data) {
+ var entry = chrome.fileSystem.getEntryById(data.id);
+ if (!entry) {
+ console.error("couldn't get file entry " + data.id);
+ return;
+ }
+ entry.file(function(file) {
+ var fr = new FileReader();
+ fr.onload = function(e) {
+ if (e.target.result != expectedText) {
+ console.error(
+ "expected '" + expectedText + "', got '" + e.target.result + "'");
+ return;
+ }
+ entry.createWriter(function(fileWriter) {
+ fileWriter.onwriteend = function(e) {
+ chrome.test.sendMessage('restartedFileAccessOK');
+ win.close();
+ };
+ fileWriter.onerror = function(e) {
+ console.error('Write failed: ' + e.toString());
+ };
+ var blob = new Blob(["doesn't matter"], {type: 'text/plain'});
+ fileWriter.write(blob);
+ });
+ };
+ fr.onerror = function(e) {
+ chrome.test.fail("error reading file");
+ };
+ fr.readAsText(file);
+ });
+ });
+});