1 // Copyright (c) 2013 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "xwalk/application/browser/application_storage_impl.h"
10 #include "base/file_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "base/json/json_file_value_serializer.h"
15 #include "base/json/json_string_value_serializer.h"
16 #include "sql/statement.h"
17 #include "sql/transaction.h"
18 #include "xwalk/application/browser/application_storage.h"
19 #include "xwalk/application/common/application_storage_constants.h"
21 namespace db_fields = xwalk::application_storage_constants;
23 namespace application {
25 const base::FilePath::CharType ApplicationStorageImpl::kDBFileName[] =
26 FILE_PATH_LITERAL("applications.db");
28 const char kPermissionSeparator = '^';
30 // Switching the JSON format DB(version 0) to SQLite backend version 1,
31 // should migrate all data from JSON DB to SQLite applications table.
32 static const int kVersionNumber = 1;
36 const std::string StoredPermissionStr[] = {
42 const base::FilePath::CharType kApplicationDataDirName[] =
43 FILE_PATH_LITERAL("Storage/ext");
45 std::string ToString(StoredPermission permission) {
46 if (permission == UNDEFINED_STORED_PERM)
47 return std::string("");
48 return StoredPermissionStr[permission];
51 StoredPermission ToPermission(const std::string& str) {
53 for (i = 0; i < UNDEFINED_STORED_PERM; ++i) {
54 if (str == StoredPermissionStr[i])
57 return static_cast<StoredPermission>(i);
60 inline const base::FilePath GetDBPath(const base::FilePath& path) {
61 return path.Append(ApplicationStorageImpl::kDBFileName);
64 // Initializes the applications table, returning true on success.
65 bool InitApplicationsTable(sql::Connection* db) {
66 sql::Transaction transaction(db);
68 // The table is named "applications", the primary key is "id".
69 if (!db->DoesTableExist(db_fields::kAppTableName)) {
70 if (!db->Execute(db_fields::kCreateAppTableOp))
73 return transaction.Commit();
76 // Permissions are stored like "bluetooth^ALLOW;calendar^DENY;contacts^ALLOW"
77 std::string ToString(StoredPermissionMap permissions) {
79 StoredPermissionMap::iterator iter;
80 for (iter = permissions.begin(); iter != permissions.end(); ++iter) {
83 str += (iter->first + kPermissionSeparator + ToString(iter->second));
88 StoredPermissionMap ToPermissionMap(const std::string& str) {
89 StoredPermissionMap map;
90 std::vector<std::string> vec;
91 base::SplitString(str, ';', &vec);
93 for (std::vector<std::string>::iterator iter = vec.begin();
94 iter != vec.end(); ++iter) {
95 std::vector<std::string> perm_item;
96 base::SplitString(*iter, kPermissionSeparator, &perm_item);
97 if (perm_item.size() != 2) {
98 LOG(ERROR) << "Permission format error! Corrupted database?";
102 map[perm_item[0]] = ToPermission(perm_item[1]);
108 bool InitPermissionsTable(sql::Connection* db) {
109 sql::Transaction transaction(db);
111 if (!db->DoesTableExist(db_fields::kPermissionTableName)) {
112 if (!db->Execute(db_fields::kCreatePermissionTableOp))
115 return transaction.Commit();
119 bool InitGarbageCollectionTable(sql::Connection* db) {
120 sql::Transaction transaction(db);
122 if (!db->DoesTableExist(db_fields::kGarbageCollectionTableName)) {
123 if (!db->Execute(db_fields::kCreateGarbageCollectionTableOp) ||
124 !db->Execute(db_fields::kCreateGarbageCollectionTriggersOp))
128 return transaction.Commit();
131 bool Insert(scoped_refptr<ApplicationData> application,
132 ApplicationData::ApplicationDataMap& applications) {
133 return applications.insert(
134 std::pair<std::string, scoped_refptr<ApplicationData> >(
135 application->ID(), application)).second;
138 base::FilePath GetAppDataPath(
139 const base::FilePath& base_path, const std::string& app_id) {
140 return base_path.Append(kApplicationDataDirName).Append(app_id);
145 ApplicationStorageImpl::ApplicationStorageImpl(const base::FilePath& path)
147 db_initialized_(false) {
148 // Ensure the parent directory for database file is created before reading
150 if (!base::PathExists(path) && !base::CreateDirectory(path))
154 bool ApplicationStorageImpl::UpgradeToVersion1(const base::FilePath& v0_file) {
155 JSONFileValueSerializer serializer(v0_file);
158 base::Value* old_db = serializer.Deserialize(&error_code, &error);
160 LOG(ERROR) << "Unable to read applications information from JSON DB, "
161 "the error message is: "
166 scoped_ptr<base::DictionaryValue> value;
167 for (base::DictionaryValue::Iterator it(
168 *static_cast<base::DictionaryValue*>(old_db));
169 !it.IsAtEnd(); it.Advance()) {
170 value.reset(static_cast<base::DictionaryValue*>(it.value().DeepCopy()));
171 base::DictionaryValue* manifest;
172 value->GetDictionary("manifest", &manifest);
174 value->GetString("path", &path);
176 scoped_refptr<ApplicationData> application =
177 ApplicationData::Create(base::FilePath::FromUTF8Unsafe(path),
183 LOG(ERROR) << "Unable to migrate the information to Version 1: " << error;
188 value->GetDouble("install_time", &install_time);
189 if (!AddApplication(application, base::Time::FromDoubleT(install_time)))
192 meta_table_.SetVersionNumber(1);
197 ApplicationStorageImpl::~ApplicationStorageImpl() {
200 bool ApplicationStorageImpl::Init(
201 ApplicationData::ApplicationDataMap& applications) {
202 bool does_db_exist = base::PathExists(GetDBPath(data_path_));
203 scoped_ptr<sql::Connection> sqlite_db(new sql::Connection);
204 if (!sqlite_db->Open(GetDBPath(data_path_))) {
205 LOG(ERROR) << "Unable to open applications DB.";
208 sqlite_db->Preload();
210 if (!meta_table_.Init(sqlite_db.get(), kVersionNumber, kVersionNumber) ||
211 meta_table_.GetVersionNumber() != kVersionNumber) {
212 LOG(ERROR) << "Unable to init the META table.";
216 if (!InitApplicationsTable(sqlite_db.get())) {
217 LOG(ERROR) << "Unable to open applications table.";
221 if (!InitPermissionsTable(sqlite_db.get())) {
222 LOG(ERROR) << "Unable to open registered permissions table.";
226 if (!InitGarbageCollectionTable(sqlite_db.get())) {
227 LOG(ERROR) << "Unable to open garbage collection table.";
231 if (!sqlite_db->Execute("PRAGMA foreign_keys=ON")) {
232 LOG(ERROR) << "Unable to enforce foreign key contraints.";
236 sqlite_db_.reset(sqlite_db.release());
238 db_initialized_ = (sqlite_db_ && sqlite_db_->is_open());
240 base::FilePath v0_file = data_path_.Append(
241 FILE_PATH_LITERAL("applications_db"));
242 if (base::PathExists(v0_file) &&
244 if (!UpgradeToVersion1(v0_file)) {
245 LOG(ERROR) << "Unable to migrate database from JSON format to SQLite.";
248 // After migrated to SQLite, delete the old JSON DB file is safe,
249 // since all information has been migrated and it will not be used anymore.
250 if (!base::DeleteFile(v0_file, false)) {
251 LOG(ERROR) << "Unalbe to delete old JSON DB file.";
256 db_initialized_ = GetInstalledApplications(applications);
258 // TODO(xiang): move this to file thread and only enable application install
259 // after this garbage collection finished.
260 if (!CollectGarbageApplications())
261 LOG(ERROR) << "Unable to collection garbage applications.";
263 return db_initialized_;
266 bool ApplicationStorageImpl::GetInstalledApplications(
267 ApplicationData::ApplicationDataMap& applications) {
268 if (!db_initialized_) {
269 LOG(ERROR) << "The database haven't initilized.";
273 sql::Statement smt(sqlite_db_->GetUniqueStatement(
274 db_fields::kGetAllRowsFromAppTableOp));
278 std::string error_msg;
280 std::string id = smt.ColumnString(0);
283 std::string manifest_str = smt.ColumnString(1);
284 JSONStringValueSerializer serializer(&manifest_str);
285 scoped_ptr<base::DictionaryValue> manifest(
286 static_cast<base::DictionaryValue*>(
287 serializer.Deserialize(&error_code, &error_msg)));
290 LOG(ERROR) << "An error occured when deserializing the manifest, "
291 "the error message is: "
295 std::string path = smt.ColumnString(2);
296 double install_time = smt.ColumnDouble(3);
299 scoped_refptr<ApplicationData> application =
300 ApplicationData::Create(
301 base::FilePath::FromUTF8Unsafe(path),
307 LOG(ERROR) << "Load appliation error: " << error;
311 application->install_time_ = base::Time::FromDoubleT(install_time);
313 application->permission_map_ = ToPermissionMap(smt.ColumnString(5));
315 if (!Insert(application, applications)) {
316 LOG(ERROR) << "An error occurred while"
317 "initializing the application cache data.";
325 bool ApplicationStorageImpl::AddApplication(const ApplicationData* application,
326 const base::Time& install_time) {
327 if (!db_initialized_) {
328 LOG(ERROR) << "The database haven't initialized.";
332 return (SetApplicationValue(
333 application, install_time, db_fields::kSetApplicationWithBindOp) &&
334 SetPermissions(application->ID(), application->permission_map_));
337 bool ApplicationStorageImpl::UpdateApplication(
338 ApplicationData* application, const base::Time& install_time) {
339 if (!db_initialized_) {
340 LOG(ERROR) << "The database haven't initialized.";
344 if (SetApplicationValue(
345 application, install_time, db_fields::kUpdateApplicationWithBindOp) &&
346 UpdatePermissions(application->ID(), application->permission_map_)) {
347 application->is_dirty_ = false;
354 bool ApplicationStorageImpl::RemoveApplication(const std::string& id) {
355 if (!db_initialized_) {
356 LOG(ERROR) << "The database haven't initialized.";
360 sql::Transaction transaction(sqlite_db_.get());
361 if (!transaction.Begin())
364 sql::Statement smt(sqlite_db_->GetUniqueStatement(
365 db_fields::kDeleteApplicationWithBindOp));
366 smt.BindString(0, id);
368 LOG(ERROR) << "Could not delete application "
369 "information from DB.";
373 return transaction.Commit();
376 bool ApplicationStorageImpl::SetApplicationValue(
377 const ApplicationData* application,
378 const base::Time& install_time,
379 const std::string& operation) {
381 LOG(ERROR) << "A value is needed when inserting/updating in DB.";
385 std::string manifest;
386 JSONStringValueSerializer serializer(&manifest);
387 if (!serializer.Serialize(*(application->GetManifest()->value()))) {
388 LOG(ERROR) << "An error occured when serializing the manifest value.";
392 sql::Transaction transaction(sqlite_db_.get());
393 if (!transaction.Begin())
396 sql::Statement smt(sqlite_db_->GetUniqueStatement(operation.c_str()));
397 if (!smt.is_valid()) {
398 LOG(ERROR) << "Unable to insert/update application info in DB.";
401 smt.BindString(0, manifest);
402 smt.BindString(1, application->Path().AsUTF8Unsafe());
403 smt.BindDouble(2, install_time.ToDoubleT());
404 smt.BindString(3, application->ID());
406 LOG(ERROR) << "An error occured when inserting/updating "
407 "application info in DB.";
411 return transaction.Commit();
414 bool ApplicationStorageImpl::SetPermissions(const std::string& id,
415 const StoredPermissionMap& permissions) {
416 if (!db_initialized_) {
417 LOG(ERROR) << "Database is not initialized.";
420 return SetPermissionsValue(id, permissions,
421 db_fields::kInsertPermissionsWithBindOp);
424 bool ApplicationStorageImpl::UpdatePermissions(const std::string& id,
425 const StoredPermissionMap& permissions) {
426 if (!db_initialized_) {
427 LOG(ERROR) << "Database is not initialized.";
430 if (permissions.empty())
431 return RevokePermissions(id);
433 return SetPermissionsValue(id, permissions,
434 db_fields::kUpdatePermissionsWithBindOp);
437 bool ApplicationStorageImpl::RevokePermissions(const std::string& id) {
438 sql::Transaction transaction(sqlite_db_.get());
439 if (!transaction.Begin())
442 sql::Statement statement(sqlite_db_->GetUniqueStatement(
443 db_fields::kDeletePermissionsWithBindOp));
444 statement.BindString(0, id);
446 if (!statement.Run()) {
448 "An error occurred while removing permissions.";
451 return transaction.Commit();
454 bool ApplicationStorageImpl::SetPermissionsValue(
455 const std::string& id,
456 const StoredPermissionMap& permissions,
457 const std::string& operation) {
458 sql::Transaction transaction(sqlite_db_.get());
459 std::string permission_str = ToString(permissions);
461 if (!transaction.Begin())
464 sql::Statement statement(sqlite_db_->GetUniqueStatement(
466 statement.BindString(0, permission_str);
467 statement.BindString(1, id);
468 if (!statement.Run()) {
470 "An error occurred while inserting permissions.";
473 return transaction.Commit();
476 bool ApplicationStorageImpl::CollectGarbageApplications() {
477 sql::Transaction transaction(sqlite_db_.get());
478 if (!transaction.Begin())
481 sql::Statement smt(sqlite_db_->GetUniqueStatement(
482 db_fields::kGetAllRowsFromGarbageCollectionTableOp));
487 const std::string app_id = smt.ColumnString(0);
488 base::FilePath app_data_path = GetAppDataPath(data_path_, app_id);
489 if (base::DirectoryExists(app_data_path) &&
490 !base::DeleteFile(app_data_path, true)) {
491 LOG(ERROR) << "Error occurred while trying to remove application data.";
495 sql::Statement del_smt(sqlite_db_->GetUniqueStatement(
496 db_fields::kDeleteGarbageAppIdWithBindOp));
497 del_smt.BindString(0, app_id);
498 if (!del_smt.Run()) {
499 LOG(ERROR) << "Could not delete app_id from garbage table.";
504 return transaction.Commit();
507 } // namespace application