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 kEventSeparator = ';';
29 const char kPermissionSeparator = '^';
31 // Switching the JSON format DB(version 0) to SQLite backend version 1,
32 // should migrate all data from JSON DB to SQLite applications table.
33 static const int kVersionNumber = 1;
37 const std::string StoredPermissionStr[] = {
43 const base::FilePath::CharType kApplicationDataDirName[] =
44 FILE_PATH_LITERAL("Storage/ext");
46 std::string ToString(StoredPermission permission) {
47 if (permission == UNDEFINED_STORED_PERM)
48 return std::string("");
49 return StoredPermissionStr[permission];
52 StoredPermission ToPermission(const std::string& str) {
54 for (i = 0; i < UNDEFINED_STORED_PERM; ++i) {
55 if (str == StoredPermissionStr[i])
58 return static_cast<StoredPermission>(i);
61 inline const base::FilePath GetDBPath(const base::FilePath& path) {
62 return path.Append(ApplicationStorageImpl::kDBFileName);
65 // Initializes the applications table, returning true on success.
66 bool InitApplicationsTable(sql::Connection* db) {
67 sql::Transaction transaction(db);
69 // The table is named "applications", the primary key is "id".
70 if (!db->DoesTableExist(db_fields::kAppTableName)) {
71 if (!db->Execute(db_fields::kCreateAppTableOp))
74 return transaction.Commit();
77 bool InitEventsTable(sql::Connection* db) {
78 sql::Transaction transaction(db);
80 if (!db->DoesTableExist(db_fields::kEventTableName)) {
81 if (!db->Execute(db_fields::kCreateEventTableOp))
84 return transaction.Commit();
87 // Permissions are stored like "bluetooth^ALLOW;calendar^DENY;contacts^ALLOW"
88 std::string ToString(StoredPermissionMap permissions) {
90 StoredPermissionMap::iterator iter;
91 for (iter = permissions.begin(); iter != permissions.end(); ++iter) {
94 str += (iter->first + kPermissionSeparator + ToString(iter->second));
99 StoredPermissionMap ToPermissionMap(const std::string& str) {
100 StoredPermissionMap map;
101 std::vector<std::string> vec;
102 base::SplitString(str, ';', &vec);
104 for (std::vector<std::string>::iterator iter = vec.begin();
105 iter != vec.end(); ++iter) {
106 std::vector<std::string> perm_item;
107 base::SplitString(*iter, kPermissionSeparator, &perm_item);
108 if (perm_item.size() != 2) {
109 LOG(ERROR) << "Permission format error! Corrupted database?";
113 map[perm_item[0]] = ToPermission(perm_item[1]);
119 bool InitPermissionsTable(sql::Connection* db) {
120 sql::Transaction transaction(db);
122 if (!db->DoesTableExist(db_fields::kPermissionTableName)) {
123 if (!db->Execute(db_fields::kCreatePermissionTableOp))
126 return transaction.Commit();
130 bool InitGarbageCollectionTable(sql::Connection* db) {
131 sql::Transaction transaction(db);
133 if (!db->DoesTableExist(db_fields::kGarbageCollectionTableName)) {
134 if (!db->Execute(db_fields::kCreateGarbageCollectionTableOp) ||
135 !db->Execute(db_fields::kCreateGarbageCollectionTriggersOp))
139 return transaction.Commit();
142 bool Insert(scoped_refptr<ApplicationData> application,
143 ApplicationData::ApplicationDataMap& applications) {
144 return applications.insert(
145 std::pair<std::string, scoped_refptr<ApplicationData> >(
146 application->ID(), application)).second;
149 base::FilePath GetAppDataPath(
150 const base::FilePath& base_path, const std::string& app_id) {
151 return base_path.Append(kApplicationDataDirName).Append(app_id);
156 ApplicationStorageImpl::ApplicationStorageImpl(const base::FilePath& path)
158 db_initialized_(false) {
159 // Ensure the parent directory for database file is created before reading
161 if (!base::PathExists(path) && !base::CreateDirectory(path))
165 bool ApplicationStorageImpl::UpgradeToVersion1(const base::FilePath& v0_file) {
166 JSONFileValueSerializer serializer(v0_file);
169 base::Value* old_db = serializer.Deserialize(&error_code, &error);
171 LOG(ERROR) << "Unable to read applications information from JSON DB, "
172 "the error message is: "
177 scoped_ptr<base::DictionaryValue> value;
178 for (base::DictionaryValue::Iterator it(
179 *static_cast<base::DictionaryValue*>(old_db));
180 !it.IsAtEnd(); it.Advance()) {
181 value.reset(static_cast<base::DictionaryValue*>(it.value().DeepCopy()));
182 base::DictionaryValue* manifest;
183 value->GetDictionary("manifest", &manifest);
185 value->GetString("path", &path);
187 scoped_refptr<ApplicationData> application =
188 ApplicationData::Create(base::FilePath::FromUTF8Unsafe(path),
194 LOG(ERROR) << "Unable to migrate the information to Version 1: " << error;
199 value->GetDouble("install_time", &install_time);
200 if (!AddApplication(application, base::Time::FromDoubleT(install_time)))
203 meta_table_.SetVersionNumber(1);
208 ApplicationStorageImpl::~ApplicationStorageImpl() {
211 bool ApplicationStorageImpl::Init(
212 ApplicationData::ApplicationDataMap& applications) {
213 bool does_db_exist = base::PathExists(GetDBPath(data_path_));
214 scoped_ptr<sql::Connection> sqlite_db(new sql::Connection);
215 if (!sqlite_db->Open(GetDBPath(data_path_))) {
216 LOG(ERROR) << "Unable to open applications DB.";
219 sqlite_db->Preload();
221 if (!meta_table_.Init(sqlite_db.get(), kVersionNumber, kVersionNumber) ||
222 meta_table_.GetVersionNumber() != kVersionNumber) {
223 LOG(ERROR) << "Unable to init the META table.";
227 if (!InitApplicationsTable(sqlite_db.get())) {
228 LOG(ERROR) << "Unable to open applications table.";
232 if (!InitEventsTable(sqlite_db.get())) {
233 LOG(ERROR) << "Unable to open registered events table.";
237 if (!InitPermissionsTable(sqlite_db.get())) {
238 LOG(ERROR) << "Unable to open registered permissions table.";
242 if (!InitGarbageCollectionTable(sqlite_db.get())) {
243 LOG(ERROR) << "Unable to open garbage collection table.";
247 if (!sqlite_db->Execute("PRAGMA foreign_keys=ON")) {
248 LOG(ERROR) << "Unable to enforce foreign key contraints.";
252 sqlite_db_.reset(sqlite_db.release());
254 db_initialized_ = (sqlite_db_ && sqlite_db_->is_open());
256 base::FilePath v0_file = data_path_.Append(
257 FILE_PATH_LITERAL("applications_db"));
258 if (base::PathExists(v0_file) &&
260 if (!UpgradeToVersion1(v0_file)) {
261 LOG(ERROR) << "Unable to migrate database from JSON format to SQLite.";
264 // After migrated to SQLite, delete the old JSON DB file is safe,
265 // since all information has been migrated and it will not be used anymore.
266 if (!base::DeleteFile(v0_file, false)) {
267 LOG(ERROR) << "Unalbe to delete old JSON DB file.";
272 db_initialized_ = GetInstalledApplications(applications);
274 // TODO(xiang): move this to file thread and only enable application install
275 // after this garbage collection finished.
276 if (!CollectGarbageApplications())
277 LOG(ERROR) << "Unable to collection garbage applications.";
279 return db_initialized_;
282 bool ApplicationStorageImpl::GetInstalledApplications(
283 ApplicationData::ApplicationDataMap& applications) {
284 if (!db_initialized_) {
285 LOG(ERROR) << "The database haven't initilized.";
289 sql::Statement smt(sqlite_db_->GetUniqueStatement(
290 db_fields::kGetAllRowsFromAppEventTableOp));
294 std::string error_msg;
296 std::string id = smt.ColumnString(0);
299 std::string manifest_str = smt.ColumnString(1);
300 JSONStringValueSerializer serializer(&manifest_str);
301 scoped_ptr<base::DictionaryValue> manifest(
302 static_cast<base::DictionaryValue*>(
303 serializer.Deserialize(&error_code, &error_msg)));
306 LOG(ERROR) << "An error occured when deserializing the manifest, "
307 "the error message is: "
311 std::string path = smt.ColumnString(2);
312 double install_time = smt.ColumnDouble(3);
313 std::vector<std::string> events;
314 base::SplitString(smt.ColumnString(4), kEventSeparator, &events);
317 scoped_refptr<ApplicationData> application =
318 ApplicationData::Create(
319 base::FilePath::FromUTF8Unsafe(path),
325 LOG(ERROR) << "Load appliation error: " << error;
329 application->install_time_ = base::Time::FromDoubleT(install_time);
331 if (!events.empty()) {
332 application->events_ =
333 std::set<std::string>(events.begin(), events.end());
336 application->permission_map_ = ToPermissionMap(smt.ColumnString(5));
338 if (!Insert(application, applications)) {
339 LOG(ERROR) << "An error occurred while"
340 "initializing the application cache data.";
348 bool ApplicationStorageImpl::AddApplication(const ApplicationData* application,
349 const base::Time& install_time) {
350 if (!db_initialized_) {
351 LOG(ERROR) << "The database haven't initialized.";
355 return (SetApplicationValue(
356 application, install_time, db_fields::kSetApplicationWithBindOp) &&
357 SetEvents(application->ID(), application->GetEvents()) &&
358 SetPermissions(application->ID(), application->permission_map_));
361 bool ApplicationStorageImpl::UpdateApplication(
362 ApplicationData* application, const base::Time& install_time) {
363 if (!db_initialized_) {
364 LOG(ERROR) << "The database haven't initialized.";
368 if (SetApplicationValue(
369 application, install_time, db_fields::kUpdateApplicationWithBindOp) &&
370 UpdateEvents(application->ID(), application->GetEvents()) &&
371 UpdatePermissions(application->ID(), application->permission_map_)) {
372 application->is_dirty_ = false;
379 bool ApplicationStorageImpl::RemoveApplication(const std::string& id) {
380 if (!db_initialized_) {
381 LOG(ERROR) << "The database haven't initialized.";
385 sql::Transaction transaction(sqlite_db_.get());
386 if (!transaction.Begin())
389 sql::Statement smt(sqlite_db_->GetUniqueStatement(
390 db_fields::kDeleteApplicationWithBindOp));
391 smt.BindString(0, id);
393 LOG(ERROR) << "Could not delete application "
394 "information from DB.";
398 return transaction.Commit();
401 bool ApplicationStorageImpl::SetApplicationValue(
402 const ApplicationData* application,
403 const base::Time& install_time,
404 const std::string& operation) {
406 LOG(ERROR) << "A value is needed when inserting/updating in DB.";
410 std::string manifest;
411 JSONStringValueSerializer serializer(&manifest);
412 if (!serializer.Serialize(*(application->GetManifest()->value()))) {
413 LOG(ERROR) << "An error occured when serializing the manifest value.";
417 sql::Transaction transaction(sqlite_db_.get());
418 if (!transaction.Begin())
421 sql::Statement smt(sqlite_db_->GetUniqueStatement(operation.c_str()));
422 if (!smt.is_valid()) {
423 LOG(ERROR) << "Unable to insert/update application info in DB.";
426 smt.BindString(0, manifest);
427 smt.BindString(1, application->Path().AsUTF8Unsafe());
428 smt.BindDouble(2, install_time.ToDoubleT());
429 smt.BindString(3, application->ID());
431 LOG(ERROR) << "An error occured when inserting/updating "
432 "application info in DB.";
436 return transaction.Commit();
439 bool ApplicationStorageImpl::SetEvents(const std::string& id,
440 const std::set<std::string>& events) {
441 if (!db_initialized_)
443 return SetEventsValue(id, events, db_fields::kInsertEventsWithBindOp);
446 bool ApplicationStorageImpl::UpdateEvents(
447 const std::string &id, const std::set<std::string>& events) {
448 if (!db_initialized_)
452 return DeleteEvents(id);
454 return SetEventsValue(id, events, db_fields::kUpdateEventsWithBindOp);
457 bool ApplicationStorageImpl::DeleteEvents(const std::string& id) {
458 sql::Transaction transaction(sqlite_db_.get());
459 if (!transaction.Begin())
462 sql::Statement smt(sqlite_db_->GetUniqueStatement(
463 db_fields::kDeleteEventsWithBindOp));
464 smt.BindString(0, id);
467 LOG(ERROR) << "An error occured when deleting event information from DB.";
471 return transaction.Commit();
474 bool ApplicationStorageImpl::SetEventsValue(
475 const std::string& id,
476 const std::set<std::string>& events,
477 const std::string& operation) {
478 sql::Transaction transaction(sqlite_db_.get());
479 std::string events_list(JoinString(
480 std::vector<std::string>(events.begin(), events.end()), kEventSeparator));
482 if (!transaction.Begin())
485 sql::Statement smt(sqlite_db_->GetUniqueStatement(
487 smt.BindString(0, events_list);
488 smt.BindString(1, id);
490 LOG(ERROR) << "An error occured when inserting event information into DB.";
494 return transaction.Commit();
497 bool ApplicationStorageImpl::SetPermissions(const std::string& id,
498 const StoredPermissionMap& permissions) {
499 if (!db_initialized_) {
500 LOG(ERROR) << "Database is not initialized.";
503 return SetPermissionsValue(id, permissions,
504 db_fields::kInsertPermissionsWithBindOp);
507 bool ApplicationStorageImpl::UpdatePermissions(const std::string& id,
508 const StoredPermissionMap& permissions) {
509 if (!db_initialized_) {
510 LOG(ERROR) << "Database is not initialized.";
513 if (permissions.empty())
514 return RevokePermissions(id);
516 return SetPermissionsValue(id, permissions,
517 db_fields::kUpdatePermissionsWithBindOp);
520 bool ApplicationStorageImpl::RevokePermissions(const std::string& id) {
521 sql::Transaction transaction(sqlite_db_.get());
522 if (!transaction.Begin())
525 sql::Statement statement(sqlite_db_->GetUniqueStatement(
526 db_fields::kDeletePermissionsWithBindOp));
527 statement.BindString(0, id);
529 if (!statement.Run()) {
531 "An error occurred while removing permissions.";
534 return transaction.Commit();
537 bool ApplicationStorageImpl::SetPermissionsValue(
538 const std::string& id,
539 const StoredPermissionMap& permissions,
540 const std::string& operation) {
541 sql::Transaction transaction(sqlite_db_.get());
542 std::string permission_str = ToString(permissions);
544 if (!transaction.Begin())
547 sql::Statement statement(sqlite_db_->GetUniqueStatement(
549 statement.BindString(0, permission_str);
550 statement.BindString(1, id);
551 if (!statement.Run()) {
553 "An error occurred while inserting permissions.";
556 return transaction.Commit();
559 bool ApplicationStorageImpl::CollectGarbageApplications() {
560 sql::Transaction transaction(sqlite_db_.get());
561 if (!transaction.Begin())
564 sql::Statement smt(sqlite_db_->GetUniqueStatement(
565 db_fields::kGetAllRowsFromGarbageCollectionTableOp));
570 const std::string app_id = smt.ColumnString(0);
571 base::FilePath app_data_path = GetAppDataPath(data_path_, app_id);
572 if (base::DirectoryExists(app_data_path) &&
573 !base::DeleteFile(app_data_path, true)) {
574 LOG(ERROR) << "Error occurred while trying to remove application data.";
578 sql::Statement del_smt(sqlite_db_->GetUniqueStatement(
579 db_fields::kDeleteGarbageAppIdWithBindOp));
580 del_smt.BindString(0, app_id);
581 if (!del_smt.Run()) {
582 LOG(ERROR) << "Could not delete app_id from garbage table.";
587 return transaction.Commit();
590 } // namespace application