diff options
50 files changed, 630 insertions, 215 deletions
diff --git a/components/filesystem/directory_impl.cc b/components/filesystem/directory_impl.cc index e8fab2a..c80731d 100644 --- a/components/filesystem/directory_impl.cc +++ b/components/filesystem/directory_impl.cc @@ -14,6 +14,7 @@ #include "base/memory/scoped_ptr.h" #include "build/build_config.h" #include "components/filesystem/file_impl.h" +#include "components/filesystem/lock_table.h" #include "components/filesystem/util.h" #include "mojo/common/common_type_converters.h" #include "mojo/platform_handle/platform_handle_functions.h" @@ -25,11 +26,11 @@ namespace filesystem { DirectoryImpl::DirectoryImpl(mojo::InterfaceRequest<Directory> request, base::FilePath directory_path, scoped_ptr<base::ScopedTempDir> temp_dir, - LockTable* lock_table) + scoped_refptr<LockTable> lock_table) : binding_(this, std::move(request)), directory_path_(directory_path), temp_dir_(std::move(temp_dir)), - lock_table_(lock_table) {} + lock_table_(std::move(lock_table)) {} DirectoryImpl::~DirectoryImpl() { } diff --git a/components/filesystem/directory_impl.h b/components/filesystem/directory_impl.h index 347c514..03bba30 100644 --- a/components/filesystem/directory_impl.h +++ b/components/filesystem/directory_impl.h @@ -30,7 +30,7 @@ class DirectoryImpl : public Directory { DirectoryImpl(mojo::InterfaceRequest<Directory> request, base::FilePath directory_path, scoped_ptr<base::ScopedTempDir> temp_dir, - LockTable* lock_table); + scoped_refptr<LockTable> lock_table); ~DirectoryImpl() override; void set_connection_error_handler(const mojo::Closure& error_handler) { @@ -73,7 +73,7 @@ class DirectoryImpl : public Directory { mojo::StrongBinding<Directory> binding_; base::FilePath directory_path_; scoped_ptr<base::ScopedTempDir> temp_dir_; - LockTable* lock_table_; + scoped_refptr<LockTable> lock_table_; DISALLOW_COPY_AND_ASSIGN(DirectoryImpl); }; diff --git a/components/filesystem/file_impl.cc b/components/filesystem/file_impl.cc index 21b38d7..13ebced 100644 --- a/components/filesystem/file_impl.cc +++ b/components/filesystem/file_impl.cc @@ -34,22 +34,22 @@ const size_t kMaxReadSize = 1 * 1024 * 1024; // 1 MB. FileImpl::FileImpl(mojo::InterfaceRequest<File> request, const base::FilePath& path, uint32_t flags, - LockTable* lock_table) + scoped_refptr<LockTable> lock_table) : binding_(this, std::move(request)), file_(path, flags), path_(path), - lock_table_(lock_table) { + lock_table_(std::move(lock_table)) { DCHECK(file_.IsValid()); } FileImpl::FileImpl(mojo::InterfaceRequest<File> request, const base::FilePath& path, base::File file, - LockTable* lock_table) + scoped_refptr<LockTable> lock_table) : binding_(this, std::move(request)), file_(std::move(file)), path_(path), - lock_table_(lock_table) { + lock_table_(std::move(lock_table)) { DCHECK(file_.IsValid()); } diff --git a/components/filesystem/file_impl.h b/components/filesystem/file_impl.h index 9314776..bdae38e 100644 --- a/components/filesystem/file_impl.h +++ b/components/filesystem/file_impl.h @@ -27,11 +27,11 @@ class FileImpl : public File { FileImpl(mojo::InterfaceRequest<File> request, const base::FilePath& path, uint32_t flags, - LockTable* lock_table); + scoped_refptr<LockTable> lock_table); FileImpl(mojo::InterfaceRequest<File> request, const base::FilePath& path, base::File file, - LockTable* lock_table); + scoped_refptr<LockTable> lock_table); ~FileImpl() override; // Returns whether the underlying file handle is valid. @@ -74,7 +74,7 @@ class FileImpl : public File { mojo::StrongBinding<File> binding_; base::File file_; base::FilePath path_; - LockTable* lock_table_; + scoped_refptr<LockTable> lock_table_; DISALLOW_COPY_AND_ASSIGN(FileImpl); }; diff --git a/components/filesystem/file_system_app.cc b/components/filesystem/file_system_app.cc index 9ec3806..2163351 100644 --- a/components/filesystem/file_system_app.cc +++ b/components/filesystem/file_system_app.cc @@ -52,7 +52,7 @@ bool FileSystemApp::AcceptConnection(mojo::Connection* connection) { void FileSystemApp::Create(mojo::Connection* connection, mojo::InterfaceRequest<FileSystem> request) { new FileSystemImpl(connection, std::move(request), GetUserDataDir(), - lock_table_.get()); + lock_table_); } void FileSystemApp::ShellConnectionLost() { diff --git a/components/filesystem/file_system_app.h b/components/filesystem/file_system_app.h index 1eb65c3..5e297ad 100644 --- a/components/filesystem/file_system_app.h +++ b/components/filesystem/file_system_app.h @@ -42,7 +42,7 @@ class FileSystemApp : public mojo::ShellClient, mojo::TracingImpl tracing_; - scoped_ptr<LockTable> lock_table_; + scoped_refptr<LockTable> lock_table_; DISALLOW_COPY_AND_ASSIGN(FileSystemApp); }; diff --git a/components/filesystem/file_system_impl.cc b/components/filesystem/file_system_impl.cc index f8b9594..b1eacf16 100644 --- a/components/filesystem/file_system_impl.cc +++ b/components/filesystem/file_system_impl.cc @@ -15,6 +15,7 @@ #include "base/memory/scoped_ptr.h" #include "build/build_config.h" #include "components/filesystem/directory_impl.h" +#include "components/filesystem/lock_table.h" #include "mojo/shell/public/cpp/connection.h" #include "url/gurl.h" @@ -23,10 +24,10 @@ namespace filesystem { FileSystemImpl::FileSystemImpl(mojo::Connection* connection, mojo::InterfaceRequest<FileSystem> request, base::FilePath persistent_dir, - LockTable* lock_table) + scoped_refptr<LockTable> lock_table) : remote_application_name_(connection->GetRemoteIdentity().name()), binding_(this, std::move(request)), - lock_table_(lock_table), + lock_table_(std::move(lock_table)), persistent_dir_(persistent_dir) {} FileSystemImpl::~FileSystemImpl() { diff --git a/components/filesystem/file_system_impl.h b/components/filesystem/file_system_impl.h index 7bbecd2..ff5d9bc 100644 --- a/components/filesystem/file_system_impl.h +++ b/components/filesystem/file_system_impl.h @@ -32,7 +32,7 @@ class FileSystemImpl : public FileSystem { FileSystemImpl(mojo::Connection* connection, mojo::InterfaceRequest<FileSystem> request, base::FilePath persistent_dir, - LockTable* lock_table); + scoped_refptr<LockTable> lock_table); ~FileSystemImpl() override; // |Files| implementation: @@ -46,7 +46,7 @@ class FileSystemImpl : public FileSystem { private: const std::string remote_application_name_; mojo::StrongBinding<FileSystem> binding_; - LockTable* lock_table_; + scoped_refptr<LockTable> lock_table_; base::FilePath persistent_dir_; diff --git a/components/filesystem/lock_table.h b/components/filesystem/lock_table.h index 9be4ca6..73674ac2 100644 --- a/components/filesystem/lock_table.h +++ b/components/filesystem/lock_table.h @@ -8,6 +8,7 @@ #include <set> #include "base/files/file.h" +#include "base/memory/ref_counted.h" namespace filesystem { @@ -16,10 +17,9 @@ class FileImpl; // A table of all locks held by this process. We have one global table owned by // the app, but accessible by everything just in case two connections from the // same origin try to lock the same file. -class LockTable { +class LockTable : public base::RefCounted<LockTable> { public: LockTable(); - ~LockTable(); // Locks a file. base::File::Error LockFile(FileImpl* file); @@ -33,6 +33,9 @@ class LockTable { void RemoveFromLockTable(const base::FilePath& path); private: + friend class base::RefCounted<LockTable>; + ~LockTable(); + // Open, locked files. We keep track of this so we quickly error when we try // to double lock a file. std::set<base::FilePath> locked_files_; diff --git a/components/leveldb/OWNERS b/components/leveldb/OWNERS new file mode 100644 index 0000000..4733a4f --- /dev/null +++ b/components/leveldb/OWNERS @@ -0,0 +1 @@ +erg@chromium.org diff --git a/components/leveldb/leveldb_app.cc b/components/leveldb/leveldb_app.cc index aad49e28..ac2855f 100644 --- a/components/leveldb/leveldb_app.cc +++ b/components/leveldb/leveldb_app.cc @@ -4,6 +4,7 @@ #include "components/leveldb/leveldb_app.h" +#include "base/message_loop/message_loop.h" #include "components/leveldb/leveldb_service_impl.h" #include "mojo/shell/public/cpp/connection.h" @@ -17,7 +18,6 @@ void LevelDBApp::Initialize(mojo::Connector* connector, const mojo::Identity& identity, uint32_t id) { tracing_.Initialize(connector, identity.name()); - service_.reset(new LevelDBServiceImpl); } bool LevelDBApp::AcceptConnection(mojo::Connection* connection) { @@ -31,7 +31,9 @@ void LevelDBApp::ShellConnectionLost() { } void LevelDBApp::Create(mojo::Connection* connection, - mojo::InterfaceRequest<LevelDBService> request) { + leveldb::LevelDBServiceRequest request) { + if (!service_) + service_.reset(new LevelDBServiceImpl); bindings_.AddBinding(service_.get(), std::move(request)); } diff --git a/components/leveldb/leveldb_app.h b/components/leveldb/leveldb_app.h index a2e806f..6db5194 100644 --- a/components/leveldb/leveldb_app.h +++ b/components/leveldb/leveldb_app.h @@ -29,7 +29,7 @@ class LevelDBApp : public mojo::ShellClient, // |InterfaceFactory<LevelDBService>| implementation: void Create(mojo::Connection* connection, - mojo::InterfaceRequest<LevelDBService> request) override; + leveldb::LevelDBServiceRequest request) override; mojo::TracingImpl tracing_; scoped_ptr<LevelDBService> service_; diff --git a/components/leveldb/leveldb_database_impl.cc b/components/leveldb/leveldb_database_impl.cc index efefc5a..d5e8fa6 100644 --- a/components/leveldb/leveldb_database_impl.cc +++ b/components/leveldb/leveldb_database_impl.cc @@ -28,7 +28,7 @@ uint64_t GetSafeRandomId(const std::map<uint64_t, T>& m) { } // namespace LevelDBDatabaseImpl::LevelDBDatabaseImpl( - mojo::InterfaceRequest<LevelDBDatabase> request, + leveldb::LevelDBDatabaseRequest request, scoped_ptr<MojoEnv> environment, scoped_ptr<leveldb::DB> db) : binding_(this, std::move(request)), diff --git a/components/leveldb/leveldb_database_impl.h b/components/leveldb/leveldb_database_impl.h index 5b5721c..29ff697 100644 --- a/components/leveldb/leveldb_database_impl.h +++ b/components/leveldb/leveldb_database_impl.h @@ -18,7 +18,7 @@ class MojoEnv; // The backing to a database object that we pass to our called. class LevelDBDatabaseImpl : public LevelDBDatabase { public: - LevelDBDatabaseImpl(mojo::InterfaceRequest<LevelDBDatabase> request, + LevelDBDatabaseImpl(leveldb::LevelDBDatabaseRequest request, scoped_ptr<MojoEnv> environment, scoped_ptr<leveldb::DB> db); ~LevelDBDatabaseImpl() override; diff --git a/components/leveldb/leveldb_service_impl.cc b/components/leveldb/leveldb_service_impl.cc index 404019e..baff56b 100644 --- a/components/leveldb/leveldb_service_impl.cc +++ b/components/leveldb/leveldb_service_impl.cc @@ -15,15 +15,13 @@ namespace leveldb { -LevelDBServiceImpl::LevelDBServiceImpl() - : thread_(new LevelDBFileThread) { -} +LevelDBServiceImpl::LevelDBServiceImpl() : thread_(new LevelDBFileThread) {} LevelDBServiceImpl::~LevelDBServiceImpl() {} void LevelDBServiceImpl::Open(filesystem::DirectoryPtr directory, const mojo::String& dbname, - mojo::InterfaceRequest<LevelDBDatabase> database, + leveldb::LevelDBDatabaseRequest database, const OpenCallback& callback) { // This is the place where we open a database. leveldb::Options options; diff --git a/components/leveldb/leveldb_service_impl.h b/components/leveldb/leveldb_service_impl.h index 54b2942..8d554f7 100644 --- a/components/leveldb/leveldb_service_impl.h +++ b/components/leveldb/leveldb_service_impl.h @@ -8,6 +8,7 @@ #include "base/memory/ref_counted.h" #include "components/leveldb/leveldb_file_thread.h" #include "components/leveldb/public/interfaces/leveldb.mojom.h" +#include "mojo/public/cpp/bindings/binding_set.h" namespace leveldb { @@ -20,7 +21,7 @@ class LevelDBServiceImpl : public LevelDBService { // Overridden from LevelDBService: void Open(filesystem::DirectoryPtr directory, const mojo::String& dbname, - mojo::InterfaceRequest<LevelDBDatabase> database, + leveldb::LevelDBDatabaseRequest database, const OpenCallback& callback) override; private: diff --git a/components/profile_service/BUILD.gn b/components/profile_service/BUILD.gn index cdde7a0..3ff648b 100644 --- a/components/profile_service/BUILD.gn +++ b/components/profile_service/BUILD.gn @@ -10,6 +10,8 @@ source_set("lib") { "profile_app.h", "profile_service_impl.cc", "profile_service_impl.h", + "user_id_map.cc", + "user_id_map.h", ] deps = [ @@ -21,6 +23,7 @@ source_set("lib") { "//components/profile_service/public/interfaces", "//mojo/common", "//mojo/common:common_base", + "//mojo/message_pump", "//mojo/platform_handle", "//mojo/services/tracing/public/cpp", "//mojo/shell/public/cpp", diff --git a/components/profile_service/DEPS b/components/profile_service/DEPS index 3760a3f..4e7a9d8 100644 --- a/components/profile_service/DEPS +++ b/components/profile_service/DEPS @@ -2,9 +2,10 @@ include_rules = [ "+components/filesystem", "+components/leveldb", "+mojo/common", - "+mojo/shell", + "+mojo/message_pump", "+mojo/platform_handle", "+mojo/public", "+mojo/services/tracing/public/cpp", + "+mojo/shell", "+mojo/util", ] diff --git a/components/profile_service/profile_app.cc b/components/profile_service/profile_app.cc index 27491db..a580711 100644 --- a/components/profile_service/profile_app.cc +++ b/components/profile_service/profile_app.cc @@ -4,46 +4,96 @@ #include "components/profile_service/profile_app.h" -#include "base/lazy_instance.h" +#include "base/bind.h" +#include "base/memory/weak_ptr.h" +#include "components/filesystem/lock_table.h" #include "components/leveldb/leveldb_service_impl.h" #include "components/profile_service/profile_service_impl.h" +#include "components/profile_service/user_id_map.h" +#include "mojo/public/cpp/bindings/callback.h" #include "mojo/shell/public/cpp/connection.h" namespace profile { -namespace { - -base::LazyInstance<std::map<std::string, base::FilePath>> - g_user_id_to_data_dir = LAZY_INSTANCE_INITIALIZER; - -} // namespace - -scoped_ptr<mojo::ShellClient> CreateProfileApp() { - return make_scoped_ptr(new ProfileApp); +class ProfileApp::ProfileServiceObjects + : public base::SupportsWeakPtr<ProfileServiceObjects> { + public: + // Created on the main thread. + ProfileServiceObjects(base::FilePath profile_data_dir) + : profile_data_dir_(profile_data_dir) {} + + // Destroyed on the |profile_service_runner_|. + ~ProfileServiceObjects() {} + + // Called on the |profile_service_runner_|. + void OnProfileServiceRequest(mojo::Connection* connection, + ProfileServiceRequest request) { + if (!lock_table_) + lock_table_ = new filesystem::LockTable; + profile_service_bindings_.AddBinding( + new ProfileServiceImpl(profile_data_dir_, lock_table_), + std::move(request)); + } + + private: + mojo::BindingSet<ProfileService> profile_service_bindings_; + scoped_refptr<filesystem::LockTable> lock_table_; + base::FilePath profile_data_dir_; + + DISALLOW_COPY_AND_ASSIGN(ProfileServiceObjects); +}; + +class ProfileApp::LevelDBServiceObjects + : public base::SupportsWeakPtr<LevelDBServiceObjects> { + public: + // Created on the main thread. + LevelDBServiceObjects() {} + + // Destroyed on the |leveldb_service_runner_|. + ~LevelDBServiceObjects() {} + + // Called on the |leveldb_service_runner_|. + void OnLevelDBServiceRequest(mojo::Connection* connection, + leveldb::LevelDBServiceRequest request) { + if (!leveldb_service_) + leveldb_service_.reset(new leveldb::LevelDBServiceImpl); + leveldb_bindings_.AddBinding(leveldb_service_.get(), std::move(request)); + } + + private: + // Variables that are only accessible on the |leveldb_service_runner_| thread. + scoped_ptr<leveldb::LevelDBService> leveldb_service_; + mojo::BindingSet<leveldb::LevelDBService> leveldb_bindings_; + + DISALLOW_COPY_AND_ASSIGN(LevelDBServiceObjects); +}; + +scoped_ptr<mojo::ShellClient> CreateProfileApp( + scoped_refptr<base::SingleThreadTaskRunner> profile_service_runner, + scoped_refptr<base::SingleThreadTaskRunner> leveldb_service_runner) { + return make_scoped_ptr(new ProfileApp( + std::move(profile_service_runner), + std::move(leveldb_service_runner))); } -ProfileApp::ProfileApp() - : lock_table_(new filesystem::LockTable) { -} - -ProfileApp::~ProfileApp() {} +ProfileApp::ProfileApp( + scoped_refptr<base::SingleThreadTaskRunner> profile_service_runner, + scoped_refptr<base::SingleThreadTaskRunner> leveldb_service_runner) + : profile_service_runner_(std::move(profile_service_runner)), + leveldb_service_runner_(std::move(leveldb_service_runner)) {} -// static -void ProfileApp::AssociateMojoUserIDWithProfileDir( - const std::string& user_id, - const base::FilePath& profile_data_dir) { - g_user_id_to_data_dir.Get()[user_id] = profile_data_dir; +ProfileApp::~ProfileApp() { + profile_service_runner_->DeleteSoon(FROM_HERE, profile_objects_.release()); + leveldb_service_runner_->DeleteSoon(FROM_HERE, leveldb_objects_.release()); } void ProfileApp::Initialize(mojo::Connector* connector, const mojo::Identity& identity, uint32_t id) { tracing_.Initialize(connector, identity.name()); - leveldb_service_.reset(new leveldb::LevelDBServiceImpl); - - auto it = g_user_id_to_data_dir.Get().find(identity.user_id()); - DCHECK(it != g_user_id_to_data_dir.Get().end()); - profile_data_dir_ = it->second; + profile_objects_.reset(new ProfileApp::ProfileServiceObjects( + GetProfileDirForUserID(identity.user_id()))); + leveldb_objects_.reset(new ProfileApp::LevelDBServiceObjects); } bool ProfileApp::AcceptConnection(mojo::Connection* connection) { @@ -54,16 +104,20 @@ bool ProfileApp::AcceptConnection(mojo::Connection* connection) { void ProfileApp::Create(mojo::Connection* connection, ProfileServiceRequest request) { - // No, we need one of these per connection. - new ProfileServiceImpl(connection, - std::move(request), - profile_data_dir_, - lock_table_.get()); + profile_service_runner_->PostTask( + FROM_HERE, + base::Bind(&ProfileApp::ProfileServiceObjects::OnProfileServiceRequest, + profile_objects_->AsWeakPtr(), connection, + base::Passed(&request))); } void ProfileApp::Create(mojo::Connection* connection, leveldb::LevelDBServiceRequest request) { - leveldb_bindings_.AddBinding(leveldb_service_.get(), std::move(request)); + leveldb_service_runner_->PostTask( + FROM_HERE, + base::Bind(&ProfileApp::LevelDBServiceObjects::OnLevelDBServiceRequest, + leveldb_objects_->AsWeakPtr(), connection, + base::Passed(&request))); } } // namespace profile diff --git a/components/profile_service/profile_app.h b/components/profile_service/profile_app.h index 8da3f56..2e61087 100644 --- a/components/profile_service/profile_app.h +++ b/components/profile_service/profile_app.h @@ -5,6 +5,7 @@ #ifndef COMPONENTS_PROFILE_SERVICE_PROFILE_APP_H_ #define COMPONENTS_PROFILE_SERVICE_PROFILE_APP_H_ +#include "base/memory/ref_counted.h" #include "components/filesystem/lock_table.h" #include "components/leveldb/public/interfaces/leveldb.mojom.h" #include "components/profile_service/public/interfaces/profile.mojom.h" @@ -13,46 +14,28 @@ #include "mojo/shell/public/cpp/interface_factory.h" #include "mojo/shell/public/cpp/shell_client.h" -namespace filesystem { -class LockTable; -} - namespace profile { -scoped_ptr<mojo::ShellClient> CreateProfileApp(); +scoped_ptr<mojo::ShellClient> CreateProfileApp( + scoped_refptr<base::SingleThreadTaskRunner> profile_service_runner, + scoped_refptr<base::SingleThreadTaskRunner> leveldb_service_runner); // Application which hands off per-profile services. // -// This Application serves ProfileService, and serves LevelDBService since most -// of the users of leveldb will want to write directly to the Directory -// provided by the ProfileService; we want file handling to be done in the same -// process to minimize IPC. -// -// In the future, this application will probably also offer any service that -// most Profile using applications will need, such as preferences. +// This Application serves ProfileService. In the future, this application will +// probably also offer any service that most Profile using applications will +// need, such as preferences; this class will have to be made into a +// application which is an InterfaceProvider which internally spawns threads +// for different sub-applications. class ProfileApp : public mojo::ShellClient, public mojo::InterfaceFactory<ProfileService>, public mojo::InterfaceFactory<leveldb::LevelDBService> { public: - ProfileApp(); + ProfileApp( + scoped_refptr<base::SingleThreadTaskRunner> profile_service_runner, + scoped_refptr<base::SingleThreadTaskRunner> leveldb_service_runner); ~ProfileApp() override; - // Currently, ProfileApp is run from within the chrome process. This means it - // that the ApplicationLoader is registered during MojoShellContext startup, - // even though the application itself is not started. As soon as a - // BrowserContext is created, the BrowserContext will choose a |user_id| for - // itself and call us to register the mapping from |user_id| to - // |profile_data_dir|. - // - // This data is then accessed when we get our Initialize() call. - // - // TODO(erg): This is a temporary hack until we redo how we initialize mojo - // applications inside of chrome in general; this system won't work once - // ProfileApp gets put in its own sandboxed process. - static void AssociateMojoUserIDWithProfileDir( - const std::string& user_id, - const base::FilePath& profile_data_dir); - private: // |ShellClient| override: void Initialize(mojo::Connector* connector, @@ -68,17 +51,22 @@ class ProfileApp : public mojo::ShellClient, void Create(mojo::Connection* connection, leveldb::LevelDBServiceRequest request) override; - mojo::TracingImpl tracing_; + void OnLevelDBServiceRequest(mojo::Connection* connection, + leveldb::LevelDBServiceRequest request); + void OnLevelDBServiceError(); - scoped_ptr<ProfileService> profile_service_; - mojo::BindingSet<ProfileService> profile_bindings_; + scoped_refptr<base::SingleThreadTaskRunner> profile_service_runner_; + scoped_refptr<base::SingleThreadTaskRunner> leveldb_service_runner_; - scoped_ptr<leveldb::LevelDBService> leveldb_service_; - mojo::BindingSet<leveldb::LevelDBService> leveldb_bindings_; + mojo::TracingImpl tracing_; - scoped_ptr<filesystem::LockTable> lock_table_; + // We create these two objects so we can delete them on the correct task + // runners. + class ProfileServiceObjects; + scoped_ptr<ProfileServiceObjects> profile_objects_; - base::FilePath profile_data_dir_; + class LevelDBServiceObjects; + scoped_ptr<LevelDBServiceObjects> leveldb_objects_; DISALLOW_COPY_AND_ASSIGN(ProfileApp); }; diff --git a/components/profile_service/profile_service.gyp b/components/profile_service/profile_service.gyp index 75561bde..e0676ae 100644 --- a/components/profile_service/profile_service.gyp +++ b/components/profile_service/profile_service.gyp @@ -22,6 +22,8 @@ 'profile_app.h', 'profile_service_impl.cc', 'profile_service_impl.h', + 'user_id_map.cc', + 'user_id_map.h', ], 'dependencies': [ 'profile_service_bindings', diff --git a/components/profile_service/profile_service_impl.cc b/components/profile_service/profile_service_impl.cc index b6239dd..dee44ad 100644 --- a/components/profile_service/profile_service_impl.cc +++ b/components/profile_service/profile_service_impl.cc @@ -4,36 +4,57 @@ #include "components/profile_service/profile_service_impl.h" +#include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" +#include "base/strings/utf_string_conversions.h" #include "components/filesystem/directory_impl.h" #include "components/filesystem/lock_table.h" +#include "components/filesystem/public/interfaces/types.mojom.h" #include "mojo/shell/public/cpp/connection.h" +#include "mojo/shell/public/cpp/message_loop_ref.h" namespace profile { ProfileServiceImpl::ProfileServiceImpl( - mojo::Connection* connection, - mojo::InterfaceRequest<ProfileService> request, - base::FilePath base_profile_dir, - filesystem::LockTable* lock_table) - : binding_(this, std::move(request)), - lock_table_(lock_table), - path_(base_profile_dir) { - if (!base::PathExists(path_)) - base::CreateDirectory(path_); + const base::FilePath& base_profile_dir, + const scoped_refptr<filesystem::LockTable>& lock_table) + : lock_table_(lock_table), path_(base_profile_dir) { + base::CreateDirectory(path_); } -ProfileServiceImpl::~ProfileServiceImpl() { -} +ProfileServiceImpl::~ProfileServiceImpl() {} -void ProfileServiceImpl::GetDirectory( - mojo::InterfaceRequest<filesystem::Directory> request) { +void ProfileServiceImpl::GetDirectory(filesystem::DirectoryRequest request, + const GetDirectoryCallback& callback) { new filesystem::DirectoryImpl(std::move(request), path_, scoped_ptr<base::ScopedTempDir>(), lock_table_); + callback.Run(); +} + +void ProfileServiceImpl::GetSubDirectory( + const mojo::String& sub_directory_path, + filesystem::DirectoryRequest request, + const GetSubDirectoryCallback& callback) { + // Ensure that we've made |subdirectory| recursively under our profile. + base::FilePath subdir = path_.Append( +#if defined(OS_WIN) + base::UTF8ToWide(sub_directory_path.To<std::string>())); +#else + sub_directory_path.To<std::string>()); +#endif + base::File::Error error; + if (!base::CreateDirectoryAndGetError(subdir, &error)) { + callback.Run(static_cast<filesystem::FileError>(error)); + return; + } + + new filesystem::DirectoryImpl(std::move(request), subdir, + scoped_ptr<base::ScopedTempDir>(), lock_table_); + callback.Run(filesystem::FileError::OK); } } // namespace profile diff --git a/components/profile_service/profile_service_impl.h b/components/profile_service/profile_service_impl.h index 72f7ce8..6022af0 100644 --- a/components/profile_service/profile_service_impl.h +++ b/components/profile_service/profile_service_impl.h @@ -16,24 +16,28 @@ namespace filesystem { class LockTable; } +namespace mojo { +class MessageLoopRef; +} + namespace profile { // A service which serves directories to callers. class ProfileServiceImpl : public ProfileService { public: - ProfileServiceImpl(mojo::Connection* connection, - mojo::InterfaceRequest<ProfileService> request, - base::FilePath base_profile_dir, - filesystem::LockTable* lock_table); + ProfileServiceImpl(const base::FilePath& base_profile_dir, + const scoped_refptr<filesystem::LockTable>& lock_table); ~ProfileServiceImpl() override; // Overridden from ProfileService: - void GetDirectory( - mojo::InterfaceRequest<filesystem::Directory> request) override; + void GetDirectory(filesystem::DirectoryRequest request, + const GetDirectoryCallback& callback) override; + void GetSubDirectory(const mojo::String& sub_directory_path, + filesystem::DirectoryRequest request, + const GetSubDirectoryCallback& callback) override; private: - mojo::StrongBinding<ProfileService> binding_; - filesystem::LockTable* lock_table_; + scoped_refptr<filesystem::LockTable> lock_table_; base::FilePath path_; DISALLOW_COPY_AND_ASSIGN(ProfileServiceImpl); diff --git a/components/profile_service/public/interfaces/profile.mojom b/components/profile_service/public/interfaces/profile.mojom index 898f457..3f974f2 100644 --- a/components/profile_service/public/interfaces/profile.mojom +++ b/components/profile_service/public/interfaces/profile.mojom @@ -5,6 +5,7 @@ module profile; import "components/filesystem/public/interfaces/directory.mojom"; +import "components/filesystem/public/interfaces/types.mojom"; // An encapsulation around the per-profile storage. // @@ -13,5 +14,10 @@ import "components/filesystem/public/interfaces/directory.mojom"; // it has access to is the User's profile. interface ProfileService { // Returns the user profile directory. - GetDirectory(filesystem.Directory& dir); + GetDirectory(filesystem.Directory& dir) => (); + + // Returns a subdirectory under the profile dir. Returns a filesystem error + // when we fail to create the subdirectory. + GetSubDirectory(string dir_path, filesystem.Directory& dir) + => (filesystem.FileError err); }; diff --git a/components/profile_service/user_id_map.cc b/components/profile_service/user_id_map.cc new file mode 100644 index 0000000..a5e54e4 --- /dev/null +++ b/components/profile_service/user_id_map.cc @@ -0,0 +1,29 @@ +// Copyright 2016 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. + +#include "components/profile_service/user_id_map.h" + +#include <map> + +#include "base/lazy_instance.h" + +namespace profile { + +namespace { +base::LazyInstance<std::map<std::string, base::FilePath>> + g_user_id_to_data_dir = LAZY_INSTANCE_INITIALIZER; +} // namespace + +void AssociateMojoUserIDWithProfileDir(const std::string& user_id, + const base::FilePath& profile_data_dir) { + g_user_id_to_data_dir.Get()[user_id] = profile_data_dir; +} + +base::FilePath GetProfileDirForUserID(const std::string& user_id) { + auto it = g_user_id_to_data_dir.Get().find(user_id); + DCHECK(it != g_user_id_to_data_dir.Get().end()); + return it->second; +} + +} // namespace profile diff --git a/components/profile_service/user_id_map.h b/components/profile_service/user_id_map.h new file mode 100644 index 0000000..4d5a56b --- /dev/null +++ b/components/profile_service/user_id_map.h @@ -0,0 +1,31 @@ +// Copyright 2016 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. + +#ifndef COMPONENTS_PROFILE_SERVICE_USER_ID_MAP_H_ +#define COMPONENTS_PROFILE_SERVICE_USER_ID_MAP_H_ + +#include <string> +#include "base/files/file_path.h" + +namespace profile { + +// Currently, ProfileApp is run from within the chrome process. This means that +// the ApplicationLoader is registered during MojoShellContext startup, even +// though the application itself is not started. As soon as a BrowserContext is +// created, the BrowserContext will choose a |user_id| for itself and call us +// to register the mapping from |user_id| to |profile_data_dir|. +// +// This data is then accessed when we get our Initialize() call. +// +// TODO(erg): This is a temporary hack until we redo how we initialize mojo +// applications inside of chrome in general; this system won't work once +// ProfileApp gets put in its own sandboxed process. +void AssociateMojoUserIDWithProfileDir(const std::string& user_id, + const base::FilePath& profile_data_dir); + +base::FilePath GetProfileDirForUserID(const std::string& user_id); + +} // namespace profile + +#endif // COMPONENTS_PROFILE_SERVICE_USER_ID_MAP_H_ diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index aea09ca..3acc6fd 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn @@ -120,6 +120,7 @@ source_set("browser") { deps += [ "//cc", "//cc/surfaces", + "//components/filesystem:lib", "//components/leveldb:lib", "//components/profile_service:lib", "//components/scheduler:common", diff --git a/content/browser/DEPS b/content/browser/DEPS index 650dbd4..cac7295 100644 --- a/content/browser/DEPS +++ b/content/browser/DEPS @@ -1,7 +1,8 @@ include_rules = [ # Allow inclusion of specific components that we depend on. We may only # depend on components which we share with the mojo html_viewer. - "+components/leveldb/public/interfaces", + "+components/filesystem", + "+components/leveldb", "+components/mime_util", "+components/mus/public/interfaces", "+components/mus/public", diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc index 56382ca..4b8396e 100644 --- a/content/browser/browser_context.cc +++ b/content/browser/browser_context.cc @@ -14,7 +14,7 @@ #include "base/lazy_instance.h" #include "base/rand_util.h" #include "build/build_config.h" -#include "components/profile_service/profile_app.h" +#include "components/profile_service/user_id_map.h" #include "content/browser/download/download_manager_impl.h" #include "content/browser/fileapi/chrome_blob_storage_context.h" #include "content/browser/indexed_db/indexed_db_context_impl.h" @@ -340,7 +340,7 @@ void BrowserContext::Initialize( g_used_user_ids.Get().insert(new_id); g_context_to_user_id.Get().push_back(std::make_pair(browser_context, new_id)); - profile::ProfileApp::AssociateMojoUserIDWithProfileDir(new_id, path); + profile::AssociateMojoUserIDWithProfileDir(new_id, path); browser_context->SetUserData(kMojoWasInitialized, new base::SupportsUserData::Data); } diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index ba04371..3c39e53 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc @@ -1168,7 +1168,8 @@ int BrowserMainLoop::BrowserThreadsStarted() { mojo_ipc_support_.reset(new IPC::ScopedIPCSupport( BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO) ->task_runner())); - mojo_shell_context_.reset(new MojoShellContext); + mojo_shell_context_.reset(new MojoShellContext(file_thread_->task_runner(), + db_thread_->task_runner())); #if defined(OS_MACOSX) mojo::edk::SetMachPortProvider(MachBroker::GetInstance()); #endif // defined(OS_MACOSX) diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.cc b/content/browser/dom_storage/dom_storage_context_wrapper.cc index 1bbe8af..7ab88bb 100644 --- a/content/browser/dom_storage/dom_storage_context_wrapper.cc +++ b/content/browser/dom_storage/dom_storage_context_wrapper.cc @@ -11,8 +11,13 @@ #include "base/bind_helpers.h" #include "base/files/file_path.h" #include "base/location.h" +#include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" +#include "base/strings/utf_string_conversions.h" #include "base/thread_task_runner_handle.h" +#include "components/filesystem/public/interfaces/directory.mojom.h" +#include "components/leveldb/public/interfaces/leveldb.mojom.h" +#include "components/profile_service/public/interfaces/profile.mojom.h" #include "content/browser/dom_storage/dom_storage_area.h" #include "content/browser/dom_storage/dom_storage_context_impl.h" #include "content/browser/dom_storage/dom_storage_task_runner.h" @@ -20,7 +25,9 @@ #include "content/browser/leveldb_wrapper_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/local_storage_usage_info.h" +#include "content/public/browser/mojo_app_connection.h" #include "content/public/browser/session_storage_usage_info.h" +#include "mojo/common/common_type_converters.h" namespace content { namespace { @@ -66,9 +73,163 @@ void GetSessionStorageUsageHelper( } // namespace +// Used for mojo-based LocalStorage implementation (behind --mojo-local-storage +// for now). +class DOMStorageContextWrapper::MojoState { + public: + MojoState(const std::string& mojo_user_id, const base::FilePath& subdirectory) + : mojo_user_id_(mojo_user_id), + subdirectory_(subdirectory), + connection_state_(NO_CONNECTION), + weak_ptr_factory_(this) {} + + void OpenLocalStorage(const url::Origin& origin, + LevelDBWrapperRequest request); + + private: + void LevelDBWrapperImplHasNoBindings(const url::Origin& origin) { + DCHECK(level_db_wrappers_.find(origin) != level_db_wrappers_.end()); + level_db_wrappers_.erase(origin); + } + + // Part of our asynchronous directory opening called from OpenLocalStorage(). + void OnDirectoryOpened(filesystem::FileError err); + void OnDatabaseOpened(leveldb::DatabaseError status); + + // The (possibly delayed) implementation of OpenLocalStorage(). Can be called + // directly from that function, or through |on_database_open_callbacks_|. + void BindLocalStorage(const url::Origin& origin, + LevelDBWrapperRequest request); + + // Maps between an origin and its prefixed LevelDB view. + std::map<url::Origin, scoped_ptr<LevelDBWrapperImpl>> level_db_wrappers_; + + std::string mojo_user_id_; + base::FilePath subdirectory_; + + enum ConnectionState { + NO_CONNECTION, + CONNECTION_IN_PROGRESS, + CONNECTION_FINISHED + } connection_state_; + + scoped_ptr<MojoAppConnection> profile_app_connection_; + profile::ProfileServicePtr profile_service_; + filesystem::DirectoryPtr directory_; + + leveldb::LevelDBServicePtr leveldb_service_; + leveldb::LevelDBDatabasePtr database_; + + std::vector<base::Closure> on_database_opened_callbacks_; + + base::WeakPtrFactory<MojoState> weak_ptr_factory_; +}; + +void DOMStorageContextWrapper::MojoState::OpenLocalStorage( + const url::Origin& origin, + LevelDBWrapperRequest request) { + // If we don't have a specific subdirectory where we want to put our data + // (ie, we're in incognito mode), just bind the storage with a null leveldb_ + // database. + if (subdirectory_.empty()) { + BindLocalStorage(origin, std::move(request)); + return; + } + + // If we don't have a filesystem_connection_, we'll need to establish one. + if (connection_state_ == NO_CONNECTION) { + profile_app_connection_ = MojoAppConnection::Create( + mojo_user_id_, "mojo:profile", kBrowserMojoAppUrl); + profile_app_connection_->GetInterface(&profile_service_); + + profile_service_->GetSubDirectory( + mojo::String::From(subdirectory_.AsUTF8Unsafe()), + GetProxy(&directory_), + base::Bind(&MojoState::OnDirectoryOpened, + weak_ptr_factory_.GetWeakPtr())); + connection_state_ = CONNECTION_IN_PROGRESS; + } + + if (connection_state_ == CONNECTION_IN_PROGRESS) { + // Queue this OpenLocalStorage call for when we have a level db pointer. + on_database_opened_callbacks_.push_back( + base::Bind(&MojoState::BindLocalStorage, weak_ptr_factory_.GetWeakPtr(), + origin, base::Passed(&request))); + return; + } + + BindLocalStorage(origin, std::move(request)); +} + +void DOMStorageContextWrapper::MojoState::OnDirectoryOpened( + filesystem::FileError err) { + if (err != filesystem::FileError::OK) { + // We failed to open the directory; continue with startup so that we create + // the |level_db_wrappers_|. + OnDatabaseOpened(leveldb::DatabaseError::IO_ERROR); + return; + } + + // Now that we have a directory, connect to the LevelDB service and get our + // database. + profile_app_connection_->GetInterface(&leveldb_service_); + + leveldb_service_->Open( + std::move(directory_), "leveldb", GetProxy(&database_), + base::Bind(&MojoState::OnDatabaseOpened, weak_ptr_factory_.GetWeakPtr())); +} + +void DOMStorageContextWrapper::MojoState::OnDatabaseOpened( + leveldb::DatabaseError status) { + if (status != leveldb::DatabaseError::OK) { + // If we failed to open the database, reset the service object so we pass + // null pointers to our wrappers. + database_.reset(); + leveldb_service_.reset(); + } + + // We no longer need the profile service; we've either transferred + // |directory_| to the leveldb service, or we got a file error and no more is + // possible. + directory_.reset(); + profile_service_.reset(); + + // |leveldb_| should be known to either be valid or invalid by now. Run our + // delayed bindings. + connection_state_ = CONNECTION_FINISHED; + for (size_t i = 0; i < on_database_opened_callbacks_.size(); ++i) + on_database_opened_callbacks_[i].Run(); + on_database_opened_callbacks_.clear(); +} + +void DOMStorageContextWrapper::MojoState::BindLocalStorage( + const url::Origin& origin, + LevelDBWrapperRequest request) { + if (level_db_wrappers_.find(origin) == level_db_wrappers_.end()) { + level_db_wrappers_[origin] = make_scoped_ptr(new LevelDBWrapperImpl( + database_.get(), + origin.Serialize(), + base::Bind(&MojoState::LevelDBWrapperImplHasNoBindings, + base::Unretained(this), + origin))); + } + + level_db_wrappers_[origin]->Bind(std::move(request)); +} + DOMStorageContextWrapper::DOMStorageContextWrapper( - const base::FilePath& data_path, + const std::string& mojo_user_id, + const base::FilePath& profile_path, + const base::FilePath& local_partition_path, storage::SpecialStoragePolicy* special_storage_policy) { + base::FilePath storage_dir; + if (!profile_path.empty()) + storage_dir = local_partition_path.AppendASCII(kLocalStorageDirectory); + mojo_state_.reset(new MojoState(mojo_user_id, storage_dir)); + + base::FilePath data_path; + if (!profile_path.empty()) + data_path = profile_path.Append(local_partition_path); base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool(); context_ = new DOMStorageContextImpl( data_path.empty() ? data_path @@ -84,8 +245,7 @@ DOMStorageContextWrapper::DOMStorageContextWrapper( .get())); } -DOMStorageContextWrapper::~DOMStorageContextWrapper() { -} +DOMStorageContextWrapper::~DOMStorageContextWrapper() {} void DOMStorageContextWrapper::GetLocalStorageUsage( const GetLocalStorageUsageCallback& callback) { @@ -154,6 +314,7 @@ void DOMStorageContextWrapper::SetForceKeepSessionState() { void DOMStorageContextWrapper::Shutdown() { DCHECK(context_.get()); + mojo_state_.reset(); context_->task_runner()->PostShutdownBlockingTask( FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE, @@ -167,28 +328,9 @@ void DOMStorageContextWrapper::Flush() { base::Bind(&DOMStorageContextImpl::Flush, context_)); } -void DOMStorageContextWrapper::OpenLocalStorage( - const url::Origin& origin, - mojo::InterfaceRequest<LevelDBWrapper> request) { - if (level_db_wrappers_.find(origin) == level_db_wrappers_.end()) { - level_db_wrappers_[origin] = make_scoped_ptr(new LevelDBWrapperImpl( - origin.Serialize(), - base::Bind(&DOMStorageContextWrapper::LevelDBWrapperImplHasNoBindings, - base::Unretained(this), - origin))); - } - // TODO(jam): call LevelDB service (once per this object) to open the database - // for LocalStorage and keep a pointer to it in this class. Then keep a map - // from origins to LevelDBWrapper object. Each call here for the same origin - // should use the same LevelDBWrapper object. - - level_db_wrappers_[origin]->Bind(std::move(request)); -} - -void DOMStorageContextWrapper::LevelDBWrapperImplHasNoBindings( - const url::Origin& origin) { - DCHECK(level_db_wrappers_.find(origin) != level_db_wrappers_.end()); - level_db_wrappers_.erase(origin); +void DOMStorageContextWrapper::OpenLocalStorage(const url::Origin& origin, + LevelDBWrapperRequest request) { + mojo_state_->OpenLocalStorage(origin, std::move(request)); } } // namespace content diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.h b/content/browser/dom_storage/dom_storage_context_wrapper.h index 7ec0899..4de7f5f4 100644 --- a/content/browser/dom_storage/dom_storage_context_wrapper.h +++ b/content/browser/dom_storage/dom_storage_context_wrapper.h @@ -36,7 +36,9 @@ class CONTENT_EXPORT DOMStorageContextWrapper : public: // If |data_path| is empty, nothing will be saved to disk. DOMStorageContextWrapper( + const std::string& mojo_user_id, const base::FilePath& data_path, + const base::FilePath& local_partition_path, storage::SpecialStoragePolicy* special_storage_policy); // DOMStorageContext implementation. @@ -63,9 +65,8 @@ class CONTENT_EXPORT DOMStorageContextWrapper : void Flush(); // See StoragePartitionService interface. - void OpenLocalStorage( - const url::Origin& origin, - mojo::InterfaceRequest<LevelDBWrapper> request); + void OpenLocalStorage(const url::Origin& origin, + LevelDBWrapperRequest request); private: friend class DOMStorageMessageFilter; // for access to context() @@ -75,12 +76,10 @@ class CONTENT_EXPORT DOMStorageContextWrapper : ~DOMStorageContextWrapper() override; DOMStorageContextImpl* context() const { return context_.get(); } - void LevelDBWrapperImplHasNoBindings(const url::Origin& origin); - - // Used for mojo-based LocalStorage implementation (behind - // --mojo-local-storage for now). Maps between an origin and its prefixed - // LevelDB view. - std::map<url::Origin, scoped_ptr<LevelDBWrapperImpl>> level_db_wrappers_; + // An inner class to keep all mojo-ish details together and not bleed them + // through the public interface. + class MojoState; + scoped_ptr<MojoState> mojo_state_; scoped_refptr<DOMStorageContextImpl> context_; diff --git a/content/browser/frame_host/frame_mojo_shell.cc b/content/browser/frame_host/frame_mojo_shell.cc index 74a9f13..556bfc9 100644 --- a/content/browser/frame_host/frame_mojo_shell.cc +++ b/content/browser/frame_host/frame_mojo_shell.cc @@ -9,8 +9,10 @@ #include "build/build_config.h" #include "content/browser/mojo/mojo_shell_context.h" #include "content/common/mojo/service_registry_impl.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" #include "content/public/browser/site_instance.h" #include "content/public/common/content_client.h" #include "mojo/common/url_type_converters.h" @@ -53,14 +55,13 @@ void FrameMojoShell::Connect( mojo::shell::mojom::InterfaceProviderPtr /* exposed_services */, mojo::shell::mojom::ClientProcessConnectionPtr client_process_connection, const mojo::shell::mojom::Connector::ConnectCallback& callback) { - // TODO(beng): user_id is dropped on the floor right now. Figure out what to - // do with it. mojo::shell::mojom::InterfaceProviderPtr frame_services; service_provider_bindings_.AddBinding(GetServiceRegistry(), GetProxy(&frame_services)); - + std::string mojo_user_id = BrowserContext::GetMojoUserIdFor( + frame_host_->GetProcess()->GetBrowserContext()); MojoShellContext::ConnectToApplication( - target->name, + mojo_user_id, target->name, frame_host_->GetSiteInstance()->GetSiteURL().spec(), std::move(services), std::move(frame_services), callback); } diff --git a/content/browser/leveldb_wrapper_impl.cc b/content/browser/leveldb_wrapper_impl.cc index dd8b283..623b728 100644 --- a/content/browser/leveldb_wrapper_impl.cc +++ b/content/browser/leveldb_wrapper_impl.cc @@ -9,46 +9,57 @@ namespace content { LevelDBWrapperImpl::LevelDBWrapperImpl( - const std::string& prefix, const base::Closure& no_bindings_callback) - : prefix_(prefix), no_bindings_callback_(no_bindings_callback) { + leveldb::LevelDBDatabase* database, + const std::string& prefix, + const base::Closure& no_bindings_callback) + : prefix_(prefix), + no_bindings_callback_(no_bindings_callback), + database_(database) { bindings_.set_connection_error_handler(base::Bind( &LevelDBWrapperImpl::OnConnectionError, base::Unretained(this))); } -void LevelDBWrapperImpl::Bind(mojo::InterfaceRequest<LevelDBWrapper> request) { +void LevelDBWrapperImpl::Bind(LevelDBWrapperRequest request) { bindings_.AddBinding(this, std::move(request)); } -LevelDBWrapperImpl::~LevelDBWrapperImpl() { -} +LevelDBWrapperImpl::~LevelDBWrapperImpl() {} void LevelDBWrapperImpl::Put(mojo::Array<uint8_t> key, mojo::Array<uint8_t> value, const mojo::String& source, const PutCallback& callback) { - // TODO(jam): call observers before running callback. + NOTIMPLEMENTED(); + callback.Run(leveldb::DatabaseError::NOT_SUPPORTED); } void LevelDBWrapperImpl::Delete(mojo::Array<uint8_t> key, const mojo::String& source, const DeleteCallback& callback) { - // TODO(jam): call observers before running callback. + NOTIMPLEMENTED(); + callback.Run(leveldb::DatabaseError::NOT_SUPPORTED); } void LevelDBWrapperImpl::DeleteAll(LevelDBObserverPtr observer, const mojo::String& source, const DeleteAllCallback& callback) { // TODO(jam): store observer and call it when changes occur. - // TODO(jam): call observers before running callback. + NOTIMPLEMENTED(); + callback.Run(leveldb::DatabaseError::NOT_SUPPORTED); } void LevelDBWrapperImpl::Get(mojo::Array<uint8_t> key, const GetCallback& callback) { + NOTIMPLEMENTED(); + callback.Run(leveldb::DatabaseError::NOT_SUPPORTED, mojo::Array<uint8_t>()); } void LevelDBWrapperImpl::GetAll(LevelDBObserverPtr observer, const GetAllCallback& callback) { // TODO(jam): store observer and call it when changes occur. + NOTIMPLEMENTED(); + callback.Run(leveldb::DatabaseError::NOT_SUPPORTED, + mojo::Array<KeyValuePtr>()); } void LevelDBWrapperImpl::OnConnectionError() { diff --git a/content/browser/leveldb_wrapper_impl.h b/content/browser/leveldb_wrapper_impl.h index 445fcaa..0aa5fcc 100644 --- a/content/browser/leveldb_wrapper_impl.h +++ b/content/browser/leveldb_wrapper_impl.h @@ -24,11 +24,12 @@ class LevelDBWrapperImpl : public LevelDBWrapper { public: // |no_bindings_callback| will be called when this object has no more // bindings. - LevelDBWrapperImpl(const std::string& prefix, + LevelDBWrapperImpl(leveldb::LevelDBDatabase* database, + const std::string& prefix, const base::Closure& no_bindings_callback); ~LevelDBWrapperImpl() override; - void Bind(mojo::InterfaceRequest<LevelDBWrapper> request); + void Bind(LevelDBWrapperRequest request); private: // LevelDBWrapperImpl: @@ -51,6 +52,7 @@ class LevelDBWrapperImpl : public LevelDBWrapper { std::string prefix_; mojo::BindingSet<LevelDBWrapper> bindings_; base::Closure no_bindings_callback_; + leveldb::LevelDBDatabase* database_; DISALLOW_COPY_AND_ASSIGN(LevelDBWrapperImpl); }; diff --git a/content/browser/mojo/mojo_app_connection_impl.cc b/content/browser/mojo/mojo_app_connection_impl.cc index 5182971..b2941e2a 100644 --- a/content/browser/mojo/mojo_app_connection_impl.cc +++ b/content/browser/mojo/mojo_app_connection_impl.cc @@ -21,19 +21,20 @@ void OnGotInstanceID(mojo::shell::mojom::ConnectResult result, // static scoped_ptr<MojoAppConnection> MojoAppConnection::Create( + const std::string& user_id, const std::string& name, const std::string& requestor_name) { return scoped_ptr<MojoAppConnection>( - new MojoAppConnectionImpl(name, requestor_name)); + new MojoAppConnectionImpl(user_id, name, requestor_name)); } MojoAppConnectionImpl::MojoAppConnectionImpl( + const std::string& user_id, const std::string& name, const std::string& requestor_name) { MojoShellContext::ConnectToApplication( - name, requestor_name, mojo::GetProxy(&interfaces_), - mojo::shell::mojom::InterfaceProviderPtr(), - base::Bind(&OnGotInstanceID)); + user_id, name, requestor_name, mojo::GetProxy(&interfaces_), + mojo::shell::mojom::InterfaceProviderPtr(), base::Bind(&OnGotInstanceID)); } MojoAppConnectionImpl::~MojoAppConnectionImpl() { diff --git a/content/browser/mojo/mojo_app_connection_impl.h b/content/browser/mojo/mojo_app_connection_impl.h index 60caa12..5ed747b 100644 --- a/content/browser/mojo/mojo_app_connection_impl.h +++ b/content/browser/mojo/mojo_app_connection_impl.h @@ -14,7 +14,10 @@ namespace content { // Implementation of the app connection mechanism provided to browser code. class MojoAppConnectionImpl : public MojoAppConnection { public: - MojoAppConnectionImpl(const std::string& name, + // Takes a BrowserContext and derives a mojo userid from it for this + // connection. + MojoAppConnectionImpl(const std::string& user_id, + const std::string& name, const std::string& requestor_name); ~MojoAppConnectionImpl() override; diff --git a/content/browser/mojo/mojo_shell_context.cc b/content/browser/mojo/mojo_shell_context.cc index 80857cd..2243806 100644 --- a/content/browser/mojo/mojo_shell_context.cc +++ b/content/browser/mojo/mojo_shell_context.cc @@ -6,6 +6,8 @@ #include <utility> +#include "base/bind.h" +#include "base/command_line.h" #include "base/lazy_instance.h" #include "base/macros.h" #include "base/path_service.h" @@ -14,6 +16,7 @@ #include "components/profile_service/profile_app.h" #include "content/browser/gpu/gpu_process_host.h" #include "content/common/gpu/gpu_process_launch_causes.h" +#include "content/common/mojo/current_thread_loader.h" #include "content/common/mojo/mojo_shell_connection_impl.h" #include "content/common/mojo/static_loader.h" #include "content/common/process_control.mojom.h" @@ -22,6 +25,7 @@ #include "content/public/browser/utility_process_host.h" #include "content/public/browser/utility_process_host_client.h" #include "content/public/common/content_client.h" +#include "content/public/common/content_switches.h" #include "content/public/common/service_registry.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/bindings/string.h" @@ -160,6 +164,7 @@ class MojoShellContext::Proxy { ~Proxy() {} void ConnectToApplication( + const std::string& user_id, const std::string& name, const std::string& requestor_name, mojo::shell::mojom::InterfaceProviderRequest request, @@ -168,7 +173,7 @@ class MojoShellContext::Proxy { if (task_runner_ == base::ThreadTaskRunnerHandle::Get()) { if (shell_context_) { shell_context_->ConnectToApplicationOnOwnThread( - name, requestor_name, std::move(request), + user_id, name, requestor_name, std::move(request), std::move(exposed_services), callback); } } else { @@ -177,9 +182,9 @@ class MojoShellContext::Proxy { task_runner_->PostTask( FROM_HERE, base::Bind(&MojoShellContext::ConnectToApplicationOnOwnThread, - base::Unretained(shell_context_), name, requestor_name, - base::Passed(&request), base::Passed(&exposed_services), - callback)); + base::Unretained(shell_context_), user_id, name, + requestor_name, base::Passed(&request), + base::Passed(&exposed_services), callback)); } } @@ -199,7 +204,9 @@ void MojoShellContext::SetApplicationsForTest( g_applications_for_test = apps; } -MojoShellContext::MojoShellContext() { +MojoShellContext::MojoShellContext( + scoped_refptr<base::SingleThreadTaskRunner> file_thread, + scoped_refptr<base::SingleThreadTaskRunner> db_thread) { proxy_.Get().reset(new Proxy(this)); scoped_refptr<base::SingleThreadTaskRunner> file_task_runner = @@ -253,10 +260,14 @@ MojoShellContext::MojoShellContext() { shell_->SetLoaderForName(make_scoped_ptr(new GpuProcessLoader), "mojo:media"); #endif - base::Callback<scoped_ptr<mojo::ShellClient>()> profile_callback = - base::Bind(&profile::CreateProfileApp); - shell_->SetLoaderForName( - make_scoped_ptr(new StaticLoader(profile_callback)), "mojo:profile"); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kMojoLocalStorage)) { + base::Callback<scoped_ptr<mojo::ShellClient>()> profile_callback = + base::Bind(&profile::CreateProfileApp, file_thread, db_thread); + shell_->SetLoaderForName( + make_scoped_ptr(new CurrentThreadLoader(profile_callback)), + "mojo:profile"); + } if (!IsRunningInMojoShell()) { const bool is_external = false; @@ -272,26 +283,28 @@ MojoShellContext::~MojoShellContext() { // static void MojoShellContext::ConnectToApplication( + const std::string& user_id, const std::string& name, const std::string& requestor_name, mojo::shell::mojom::InterfaceProviderRequest request, mojo::shell::mojom::InterfaceProviderPtr exposed_services, const mojo::shell::mojom::Connector::ConnectCallback& callback) { - proxy_.Get()->ConnectToApplication(name, requestor_name, std::move(request), + proxy_.Get()->ConnectToApplication(user_id, name, requestor_name, + std::move(request), std::move(exposed_services), callback); } void MojoShellContext::ConnectToApplicationOnOwnThread( + const std::string& user_id, const std::string& name, const std::string& requestor_name, mojo::shell::mojom::InterfaceProviderRequest request, mojo::shell::mojom::InterfaceProviderPtr exposed_services, const mojo::shell::mojom::Connector::ConnectCallback& callback) { scoped_ptr<mojo::shell::ConnectParams> params(new mojo::shell::ConnectParams); - // TODO(beng): kRootUserID is obviously wrong. - mojo::Identity source_id(requestor_name, mojo::shell::mojom::kRootUserID); + mojo::Identity source_id(requestor_name, user_id); params->set_source(source_id); - params->set_target(mojo::Identity(name, mojo::shell::mojom::kRootUserID)); + params->set_target(mojo::Identity(name, user_id)); params->set_remote_interfaces(std::move(request)); params->set_local_interfaces(std::move(exposed_services)); params->set_connect_callback(callback); diff --git a/content/browser/mojo/mojo_shell_context.h b/content/browser/mojo/mojo_shell_context.h index 3560364..fd8da40 100644 --- a/content/browser/mojo/mojo_shell_context.h +++ b/content/browser/mojo/mojo_shell_context.h @@ -12,6 +12,7 @@ #include "base/lazy_instance.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "base/single_thread_task_runner.h" #include "content/common/content_export.h" #include "mojo/shell/public/interfaces/connector.mojom.h" #include "mojo/shell/shell.h" @@ -33,7 +34,8 @@ class CONTENT_EXPORT MojoShellContext { using StaticApplicationMap = std::map<std::string, base::Callback<scoped_ptr<mojo::ShellClient>()>>; - MojoShellContext(); + MojoShellContext(scoped_refptr<base::SingleThreadTaskRunner> file_thread, + scoped_refptr<base::SingleThreadTaskRunner> db_thread); ~MojoShellContext(); // Connects an application at |name| and gets a handle to its exposed @@ -41,6 +43,7 @@ class CONTENT_EXPORT MojoShellContext { // some Mojo application. May be called from any thread. |requestor_name| is // given to the target application as the requestor's name upon connection. static void ConnectToApplication( + const std::string& user_id, const std::string& name, const std::string& requestor_name, mojo::shell::mojom::InterfaceProviderRequest request, @@ -54,6 +57,7 @@ class CONTENT_EXPORT MojoShellContext { friend class Proxy; void ConnectToApplicationOnOwnThread( + const std::string& user_id, const std::string& name, const std::string& requestor_name, mojo::shell::mojom::InterfaceProviderRequest request, diff --git a/content/browser/mojo_shell_browsertest.cc b/content/browser/mojo_shell_browsertest.cc index 5e9eac1e..dfe8a06c 100644 --- a/content/browser/mojo_shell_browsertest.cc +++ b/content/browser/mojo_shell_browsertest.cc @@ -7,10 +7,13 @@ #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" #include "content/browser/mojo/mojo_shell_context.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/mojo_app_connection.h" +#include "content/public/browser/web_contents.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/test_mojo_app.h" #include "content/public/test/test_mojo_service.mojom.h" +#include "content/shell/browser/shell.h" #include "url/gurl.h" namespace content { @@ -24,6 +27,12 @@ class MojoShellTest : public ContentBrowserTest { MojoShellContext::SetApplicationsForTest(&test_apps_); } + protected: + std::string GetUserId() { + return BrowserContext::GetMojoUserIdFor( + shell()->web_contents()->GetBrowserContext()); + } + private: static scoped_ptr<mojo::ShellClient> CreateTestApp() { return scoped_ptr<mojo::ShellClient>(new TestMojoApp); @@ -35,8 +44,8 @@ class MojoShellTest : public ContentBrowserTest { }; IN_PROC_BROWSER_TEST_F(MojoShellTest, TestBrowserConnection) { - auto test_app = MojoAppConnection::Create(kInProcessTestMojoAppName, - kBrowserMojoAppUrl); + auto test_app = MojoAppConnection::Create( + GetUserId(), kInProcessTestMojoAppName, kBrowserMojoAppUrl); TestMojoServicePtr test_service; test_app->GetInterface(&test_service); @@ -49,7 +58,7 @@ IN_PROC_BROWSER_TEST_F(MojoShellTest, TestUtilityConnection) { // With no loader registered at this URL, the shell should spawn a utility // process and connect us to it. content_shell's utility process always hosts // a TestMojoApp at |kTestMojoAppUrl|. - auto test_app = MojoAppConnection::Create(kTestMojoAppUrl, + auto test_app = MojoAppConnection::Create(GetUserId(), kTestMojoAppUrl, kBrowserMojoAppUrl); TestMojoServicePtr test_service; test_app->GetInterface(&test_service); diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index 7a9b90e..4b4a554 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc @@ -408,12 +408,15 @@ StoragePartitionImpl::~StoragePartitionImpl() { StoragePartitionImpl* StoragePartitionImpl::Create( BrowserContext* context, bool in_memory, - const base::FilePath& partition_path) { + const base::FilePath& relative_partition_path) { // Ensure that these methods are called on the UI thread, except for // unittests where a UI thread might not have been created. DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || !BrowserThread::IsMessageLoopValid(BrowserThread::UI)); + base::FilePath partition_path = + context->GetPath().Append(relative_partition_path); + // All of the clients have to be created and registered with the // QuotaManager prior to the QuotaManger being used. We do them // all together here prior to handing out a reference to anything @@ -440,9 +443,11 @@ StoragePartitionImpl* StoragePartitionImpl::Create( BrowserThread::GetMessageLoopProxyForThread( BrowserThread::FILE).get()); - base::FilePath path = in_memory ? base::FilePath() : partition_path; + base::FilePath path = in_memory ? base::FilePath() : context->GetPath(); scoped_refptr<DOMStorageContextWrapper> dom_storage_context = - new DOMStorageContextWrapper(path, context->GetSpecialStoragePolicy()); + new DOMStorageContextWrapper(BrowserContext::GetMojoUserIdFor(context), + path, relative_partition_path, + context->GetSpecialStoragePolicy()); // BrowserMainLoop may not be initialized in unit tests. Tests will // need to inject their own task runner into the IndexedDBContext. diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h index d4bb809..1dc259a 100644 --- a/content/browser/storage_partition_impl.h +++ b/content/browser/storage_partition_impl.h @@ -131,15 +131,16 @@ class StoragePartitionImpl : public StoragePartition, FRIEND_TEST_ALL_PREFIXES(StoragePartitionImplTest, RemoveLocalStorageForLastWeek); - // The |partition_path| is the absolute path to the root of this - // StoragePartition's on-disk storage. + // |relative_partition_path| is the relative path under |profile_path| to the + // StoragePartition's on-disk-storage. // - // If |in_memory| is true, the |partition_path| is (ab)used as a way of - // distinguishing different in-memory partitions, but nothing is persisted + // If |in_memory| is true, the |relative_partition_path| is (ab)used as a way + // of distinguishing different in-memory partitions, but nothing is persisted // on to disk. - static StoragePartitionImpl* Create(BrowserContext* context, - bool in_memory, - const base::FilePath& profile_path); + static StoragePartitionImpl* Create( + BrowserContext* context, + bool in_memory, + const base::FilePath& relative_partition_path); CONTENT_EXPORT StoragePartitionImpl( BrowserContext* browser_context, diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc index 7a0dd9c..4e98e17 100644 --- a/content/browser/storage_partition_impl_map.cc +++ b/content/browser/storage_partition_impl_map.cc @@ -396,12 +396,11 @@ StoragePartitionImpl* StoragePartitionImplMap::Get( if (it != partitions_.end()) return it->second; - base::FilePath partition_path = - browser_context_->GetPath().Append( - GetStoragePartitionPath(partition_domain, partition_name)); - StoragePartitionImpl* partition = - StoragePartitionImpl::Create(browser_context_, in_memory, - partition_path); + base::FilePath relative_partition_path = + GetStoragePartitionPath(partition_domain, partition_name); + + StoragePartitionImpl* partition = StoragePartitionImpl::Create( + browser_context_, in_memory, relative_partition_path); partitions_[partition_config] = partition; partition->GetQuotaManager()->SetTemporaryStorageEvictionPolicy( diff --git a/content/common/mojo/current_thread_loader.cc b/content/common/mojo/current_thread_loader.cc new file mode 100644 index 0000000..eb64b15 --- /dev/null +++ b/content/common/mojo/current_thread_loader.cc @@ -0,0 +1,25 @@ +// Copyright 2016 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. + +#include "content/common/mojo/current_thread_loader.h" + +namespace content { + +CurrentThreadLoader::CurrentThreadLoader(const ApplicationFactory& factory) + : factory_(factory) {} + +CurrentThreadLoader::~CurrentThreadLoader() {} + +void CurrentThreadLoader::Load(const std::string& name, + mojo::shell::mojom::ShellClientRequest request) { + if (!shell_client_) { + shell_client_ = factory_.Run(); + factory_ = ApplicationFactory(); + } + + connections_.push_back(make_scoped_ptr( + new mojo::ShellConnection(shell_client_.get(), std::move(request)))); +} + +} // namespace content diff --git a/content/common/mojo/current_thread_loader.h b/content/common/mojo/current_thread_loader.h new file mode 100644 index 0000000..e5e6e35 --- /dev/null +++ b/content/common/mojo/current_thread_loader.h @@ -0,0 +1,46 @@ +// Copyright 2016 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. + +#ifndef CONTENT_COMMON_MOJO_CURRENT_THREAD_LOADER_H_ +#define CONTENT_COMMON_MOJO_CURRENT_THREAD_LOADER_H_ + +#include <vector> + +#include "base/callback.h" +#include "base/macros.h" +#include "mojo/shell/loader.h" +#include "mojo/shell/public/cpp/shell_client.h" +#include "mojo/shell/public/cpp/shell_connection.h" + +namespace content { + +// A Loader which loads a single type of app from a mojo::ShellClientFactory on +// the current thread. +class CurrentThreadLoader : public mojo::shell::Loader { + public: + using ApplicationFactory = base::Callback<scoped_ptr<mojo::ShellClient>()>; + + explicit CurrentThreadLoader(const ApplicationFactory& factory); + ~CurrentThreadLoader() override; + + // mojo::shell::Loader: + void Load(const std::string& name, + mojo::shell::mojom::ShellClientRequest request) override; + + private: + // The factory used to create new instances of the application delegate. This + // is called exactly once since all connections share a single client. + ApplicationFactory factory_; + + // Our shared shell client, passed to each connection. + scoped_ptr<mojo::ShellClient> shell_client_; + + std::vector<scoped_ptr<mojo::ShellConnection>> connections_; + + DISALLOW_COPY_AND_ASSIGN(CurrentThreadLoader); +}; + +} // namespace content + +#endif // CONTENT_COMMON_MOJO_CURRENT_THREAD_LOADER_H_ diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 67265b3..945fe25 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -7,6 +7,7 @@ '../base/base.gyp:base_static', '../cc/cc.gyp:cc', '../cc/cc.gyp:cc_surfaces', + '../components/leveldb/leveldb.gyp:leveldb_lib', '../components/mime_util/mime_util.gyp:mime_util', '../components/profile_service/profile_service.gyp:profile_service_lib', '../components/scheduler/scheduler.gyp:scheduler_common', diff --git a/content/content_common.gypi b/content/content_common.gypi index 75fbe5f..48e67a6 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -519,6 +519,8 @@ 'common/mime_registry_messages.h', 'common/mojo/channel_init.cc', 'common/mojo/channel_init.h', + 'common/mojo/current_thread_loader.cc', + 'common/mojo/current_thread_loader.h', 'common/mojo/mojo_messages.h', 'common/mojo/mojo_shell_connection_impl.cc', 'common/mojo/mojo_shell_connection_impl.h', diff --git a/content/public/browser/mojo_app_connection.h b/content/public/browser/mojo_app_connection.h index 3878825..6ac8055 100644 --- a/content/public/browser/mojo_app_connection.h +++ b/content/public/browser/mojo_app_connection.h @@ -28,9 +28,11 @@ class CONTENT_EXPORT MojoAppConnection { virtual ~MojoAppConnection() {} // Creates a new connection to the application at |name| using - // |requestor_name| to identify the requestor upon connection. This may be - // called from any thread. + // |requestor_name| to identify the requestor and |context|'s mojo userid to + // specify a profile specific application instantiation. This may be called + // from any thread. static scoped_ptr<MojoAppConnection> Create( + const std::string& user_id, const std::string& name, const std::string& requestor_name); diff --git a/mojo/mojo_services.gyp b/mojo/mojo_services.gyp index d071c60..a42243187 100644 --- a/mojo/mojo_services.gyp +++ b/mojo/mojo_services.gyp @@ -76,7 +76,7 @@ }, { # GN version: //mojo/services/tracing/public/interfaces - 'target_name': 'tracing_service_bindings_lib', + 'target_name': 'tracing_service_bindings_lib', 'type': 'static_library', 'dependencies': [ 'tracing_service_bindings_mojom', diff --git a/mojo/shell/public/cpp/message_loop_ref.h b/mojo/shell/public/cpp/message_loop_ref.h index fffb738..f678746 100644 --- a/mojo/shell/public/cpp/message_loop_ref.h +++ b/mojo/shell/public/cpp/message_loop_ref.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef MOJO_SHELL_PUBLIC_CPP_APPLICATION_RUNNER_REFERENCE_H_ -#define MOJO_SHELL_PUBLIC_CPP_APPLICATION_RUNNER_REFERENCE_H_ +#ifndef MOJO_SHELL_PUBLIC_CPP_MESSAGE_LOOP_REF_H_ +#define MOJO_SHELL_PUBLIC_CPP_MESSAGE_LOOP_REF_H_ #include "base/macros.h" #include "base/memory/scoped_ptr.h" @@ -54,4 +54,4 @@ class MessageLoopRefFactory { } // namespace mojo -#endif // MOJO_SHELL_PUBLIC_CPP_APPLICATION_RUNNER_REFERENCE_H_ +#endif // MOJO_SHELL_PUBLIC_CPP_MESSAGE_LOOP_REF_H_ |