68c1748c158af8dde68830c6ade71e235619a200
[platform/framework/web/crosswalk.git] / src / xwalk / application / browser / application_storage_impl.cc
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.
4
5 #include "xwalk/application/browser/application_storage_impl.h"
6
7 #include <string>
8 #include <vector>
9
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"
20
21 namespace db_fields = xwalk::application_storage_constants;
22 namespace xwalk {
23 namespace application {
24
25 const base::FilePath::CharType ApplicationStorageImpl::kDBFileName[] =
26     FILE_PATH_LITERAL("applications.db");
27
28 const char kEventSeparator = ';';
29 const char kPermissionSeparator = '^';
30
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;
34
35 namespace {
36
37 const std::string StoredPermissionStr[] = {
38     "ALLOW",
39     "DENY",
40     "PROMPT",
41 };
42
43 const base::FilePath::CharType kApplicationDataDirName[] =
44     FILE_PATH_LITERAL("Storage/ext");
45
46 std::string ToString(StoredPermission permission) {
47   if (permission == UNDEFINED_STORED_PERM)
48     return std::string("");
49   return StoredPermissionStr[permission];
50 }
51
52 StoredPermission ToPermission(const std::string& str) {
53   unsigned int i;
54   for (i = 0; i < UNDEFINED_STORED_PERM; ++i) {
55     if (str == StoredPermissionStr[i])
56       break;
57   }
58   return static_cast<StoredPermission>(i);
59 }
60
61 inline const base::FilePath GetDBPath(const base::FilePath& path) {
62   return path.Append(ApplicationStorageImpl::kDBFileName);
63 }
64
65 // Initializes the applications table, returning true on success.
66 bool InitApplicationsTable(sql::Connection* db) {
67   sql::Transaction transaction(db);
68   transaction.Begin();
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))
72       return false;
73   }
74   return transaction.Commit();
75 }
76
77 bool InitEventsTable(sql::Connection* db) {
78   sql::Transaction transaction(db);
79   transaction.Begin();
80   if (!db->DoesTableExist(db_fields::kEventTableName)) {
81     if (!db->Execute(db_fields::kCreateEventTableOp))
82      return false;
83   }
84   return transaction.Commit();
85 }
86
87 // Permissions are stored like "bluetooth^ALLOW;calendar^DENY;contacts^ALLOW"
88 std::string ToString(StoredPermissionMap permissions) {
89   std::string str;
90   StoredPermissionMap::iterator iter;
91   for (iter = permissions.begin(); iter != permissions.end(); ++iter) {
92     if (!str.empty())
93       str += ";";
94     str += (iter->first + kPermissionSeparator + ToString(iter->second));
95   }
96   return str;
97 }
98
99 StoredPermissionMap ToPermissionMap(const std::string& str) {
100   StoredPermissionMap map;
101   std::vector<std::string> vec;
102   base::SplitString(str, ';', &vec);
103   if (!vec.empty()) {
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?";
110         map.clear();
111         break;
112       }
113       map[perm_item[0]] = ToPermission(perm_item[1]);
114     }
115   }
116   return map;
117 }
118
119 bool InitPermissionsTable(sql::Connection* db) {
120   sql::Transaction transaction(db);
121   transaction.Begin();
122   if (!db->DoesTableExist(db_fields::kPermissionTableName)) {
123     if (!db->Execute(db_fields::kCreatePermissionTableOp))
124      return false;
125   }
126   return transaction.Commit();
127 }
128
129
130 bool InitGarbageCollectionTable(sql::Connection* db) {
131   sql::Transaction transaction(db);
132   transaction.Begin();
133   if (!db->DoesTableExist(db_fields::kGarbageCollectionTableName)) {
134     if (!db->Execute(db_fields::kCreateGarbageCollectionTableOp) ||
135         !db->Execute(db_fields::kCreateGarbageCollectionTriggersOp))
136      return false;
137   }
138
139   return transaction.Commit();
140 }
141
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;
147 }
148
149 base::FilePath GetAppDataPath(
150     const base::FilePath& base_path, const std::string& app_id) {
151   return base_path.Append(kApplicationDataDirName).Append(app_id);
152 }
153
154 }  // namespace
155
156 ApplicationStorageImpl::ApplicationStorageImpl(const base::FilePath& path)
157     : data_path_(path),
158       db_initialized_(false) {
159   // Ensure the parent directory for database file is created before reading
160   // from it.
161   if (!base::PathExists(path) && !base::CreateDirectory(path))
162     return;
163 }
164
165 bool ApplicationStorageImpl::UpgradeToVersion1(const base::FilePath& v0_file) {
166   JSONFileValueSerializer serializer(v0_file);
167   int error_code;
168   std::string error;
169   base::Value* old_db = serializer.Deserialize(&error_code, &error);
170   if (!old_db) {
171     LOG(ERROR) << "Unable to read applications information from JSON DB, "
172                   "the error message is: "
173                << error;
174     return false;
175   }
176
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);
184     std::string path;
185     value->GetString("path", &path);
186     std::string error;
187     scoped_refptr<ApplicationData> application =
188         ApplicationData::Create(base::FilePath::FromUTF8Unsafe(path),
189                                 Manifest::INTERNAL,
190                                 *manifest,
191                                 it.key(),
192                                 &error);
193     if (!application) {
194       LOG(ERROR) << "Unable to migrate the information to Version 1: " << error;
195       return false;
196     }
197
198     double install_time;
199     value->GetDouble("install_time", &install_time);
200     if (!AddApplication(application, base::Time::FromDoubleT(install_time)))
201       return false;
202   }
203   meta_table_.SetVersionNumber(1);
204
205   return true;
206 }
207
208 ApplicationStorageImpl::~ApplicationStorageImpl() {
209 }
210
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.";
217     return false;
218   }
219   sqlite_db->Preload();
220
221   if (!meta_table_.Init(sqlite_db.get(), kVersionNumber, kVersionNumber) ||
222       meta_table_.GetVersionNumber() != kVersionNumber) {
223     LOG(ERROR) << "Unable to init the META table.";
224     return false;
225   }
226
227   if (!InitApplicationsTable(sqlite_db.get())) {
228     LOG(ERROR) << "Unable to open applications table.";
229     return false;
230   }
231
232   if (!InitEventsTable(sqlite_db.get())) {
233     LOG(ERROR) << "Unable to open registered events table.";
234     return false;
235   }
236
237   if (!InitPermissionsTable(sqlite_db.get())) {
238     LOG(ERROR) << "Unable to open registered permissions table.";
239     return false;
240   }
241
242   if (!InitGarbageCollectionTable(sqlite_db.get())) {
243     LOG(ERROR) << "Unable to open garbage collection table.";
244     return false;
245   }
246
247   if (!sqlite_db->Execute("PRAGMA foreign_keys=ON")) {
248     LOG(ERROR) << "Unable to enforce foreign key contraints.";
249     return false;
250   }
251
252   sqlite_db_.reset(sqlite_db.release());
253
254   db_initialized_ = (sqlite_db_ && sqlite_db_->is_open());
255
256   base::FilePath v0_file = data_path_.Append(
257       FILE_PATH_LITERAL("applications_db"));
258   if (base::PathExists(v0_file) &&
259       !does_db_exist) {
260     if (!UpgradeToVersion1(v0_file)) {
261       LOG(ERROR) << "Unable to migrate database from JSON format to SQLite.";
262       return false;
263     }
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.";
268       return false;
269     }
270   }
271
272   db_initialized_ = GetInstalledApplications(applications);
273
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.";
278
279   return db_initialized_;
280 }
281
282 bool ApplicationStorageImpl::GetInstalledApplications(
283     ApplicationData::ApplicationDataMap& applications) {
284   if (!db_initialized_) {
285     LOG(ERROR) << "The database haven't initilized.";
286     return false;
287   }
288
289   sql::Statement smt(sqlite_db_->GetUniqueStatement(
290       db_fields::kGetAllRowsFromAppEventTableOp));
291   if (!smt.is_valid())
292     return false;
293
294   std::string error_msg;
295   while (smt.Step()) {
296     std::string id = smt.ColumnString(0);
297
298     int error_code;
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)));
304
305     if (!manifest) {
306       LOG(ERROR) << "An error occured when deserializing the manifest, "
307                     "the error message is: "
308                  << error_msg;
309       return false;
310     }
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);
315
316     std::string error;
317     scoped_refptr<ApplicationData> application =
318         ApplicationData::Create(
319             base::FilePath::FromUTF8Unsafe(path),
320             Manifest::INTERNAL,
321             *manifest,
322             id,
323             &error);
324     if (!application) {
325       LOG(ERROR) << "Load appliation error: " << error;
326       return false;
327     }
328
329     application->install_time_ = base::Time::FromDoubleT(install_time);
330
331     if (!events.empty()) {
332       application->events_ =
333           std::set<std::string>(events.begin(), events.end());
334     }
335
336     application->permission_map_ = ToPermissionMap(smt.ColumnString(5));
337
338     if (!Insert(application, applications)) {
339       LOG(ERROR) << "An error occurred while"
340                     "initializing the application cache data.";
341       return false;
342     }
343   }
344
345   return true;
346 }
347
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.";
352     return false;
353   }
354
355   return (SetApplicationValue(
356       application, install_time, db_fields::kSetApplicationWithBindOp) &&
357           SetEvents(application->ID(), application->GetEvents()) &&
358           SetPermissions(application->ID(), application->permission_map_));
359 }
360
361 bool ApplicationStorageImpl::UpdateApplication(
362     ApplicationData* application, const base::Time& install_time) {
363   if (!db_initialized_) {
364     LOG(ERROR) << "The database haven't initialized.";
365     return false;
366   }
367
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;
373     return true;
374   }
375
376   return false;
377 }
378
379 bool ApplicationStorageImpl::RemoveApplication(const std::string& id) {
380   if (!db_initialized_) {
381     LOG(ERROR) << "The database haven't initialized.";
382     return false;
383   }
384
385   sql::Transaction transaction(sqlite_db_.get());
386   if (!transaction.Begin())
387     return false;
388
389   sql::Statement smt(sqlite_db_->GetUniqueStatement(
390       db_fields::kDeleteApplicationWithBindOp));
391   smt.BindString(0, id);
392   if (!smt.Run()) {
393     LOG(ERROR) << "Could not delete application "
394                   "information from DB.";
395     return false;
396   }
397
398   return transaction.Commit();
399 }
400
401 bool ApplicationStorageImpl::SetApplicationValue(
402     const ApplicationData* application,
403     const base::Time& install_time,
404     const std::string& operation) {
405   if (!application) {
406     LOG(ERROR) << "A value is needed when inserting/updating in DB.";
407     return false;
408   }
409
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.";
414     return false;
415   }
416
417   sql::Transaction transaction(sqlite_db_.get());
418   if (!transaction.Begin())
419     return false;
420
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.";
424     return false;
425   }
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());
430   if (!smt.Run()) {
431     LOG(ERROR) << "An error occured when inserting/updating "
432                   "application info in DB.";
433     return false;
434   }
435
436   return transaction.Commit();
437 }
438
439 bool ApplicationStorageImpl::SetEvents(const std::string& id,
440                                        const std::set<std::string>& events) {
441   if (!db_initialized_)
442     return false;
443   return SetEventsValue(id, events, db_fields::kInsertEventsWithBindOp);
444 }
445
446 bool ApplicationStorageImpl::UpdateEvents(
447     const std::string &id, const std::set<std::string>& events) {
448   if (!db_initialized_)
449     return false;
450
451   if (events.empty())
452     return DeleteEvents(id);
453
454   return SetEventsValue(id, events, db_fields::kUpdateEventsWithBindOp);
455 }
456
457 bool ApplicationStorageImpl::DeleteEvents(const std::string& id) {
458   sql::Transaction transaction(sqlite_db_.get());
459   if (!transaction.Begin())
460     return false;
461
462   sql::Statement smt(sqlite_db_->GetUniqueStatement(
463       db_fields::kDeleteEventsWithBindOp));
464   smt.BindString(0, id);
465
466   if (!smt.Run()) {
467     LOG(ERROR) << "An error occured when deleting event information from DB.";
468     return false;
469   }
470
471   return transaction.Commit();
472 }
473
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));
481
482   if (!transaction.Begin())
483     return false;
484
485   sql::Statement smt(sqlite_db_->GetUniqueStatement(
486       operation.c_str()));
487   smt.BindString(0, events_list);
488   smt.BindString(1, id);
489   if (!smt.Run()) {
490     LOG(ERROR) << "An error occured when inserting event information into DB.";
491     return false;
492   }
493
494   return transaction.Commit();
495 }
496
497 bool ApplicationStorageImpl::SetPermissions(const std::string& id,
498     const StoredPermissionMap& permissions) {
499   if (!db_initialized_) {
500     LOG(ERROR) << "Database is not initialized.";
501     return false;
502   }
503   return SetPermissionsValue(id, permissions,
504       db_fields::kInsertPermissionsWithBindOp);
505 }
506
507 bool ApplicationStorageImpl::UpdatePermissions(const std::string& id,
508     const StoredPermissionMap& permissions) {
509   if (!db_initialized_) {
510     LOG(ERROR) << "Database is not initialized.";
511     return false;
512   }
513   if (permissions.empty())
514     return RevokePermissions(id);
515
516   return SetPermissionsValue(id, permissions,
517       db_fields::kUpdatePermissionsWithBindOp);
518 }
519
520 bool ApplicationStorageImpl::RevokePermissions(const std::string& id) {
521   sql::Transaction transaction(sqlite_db_.get());
522   if (!transaction.Begin())
523     return false;
524
525   sql::Statement statement(sqlite_db_->GetUniqueStatement(
526       db_fields::kDeletePermissionsWithBindOp));
527   statement.BindString(0, id);
528
529   if (!statement.Run()) {
530     LOG(ERROR) <<
531         "An error occurred while removing permissions.";
532     return false;
533   }
534   return transaction.Commit();
535 }
536
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);
543
544   if (!transaction.Begin())
545     return false;
546
547   sql::Statement statement(sqlite_db_->GetUniqueStatement(
548       operation.c_str()));
549   statement.BindString(0, permission_str);
550   statement.BindString(1, id);
551   if (!statement.Run()) {
552     LOG(ERROR) <<
553         "An error occurred while inserting permissions.";
554     return false;
555   }
556   return transaction.Commit();
557 }
558
559 bool ApplicationStorageImpl::CollectGarbageApplications() {
560   sql::Transaction transaction(sqlite_db_.get());
561   if (!transaction.Begin())
562     return false;
563
564   sql::Statement smt(sqlite_db_->GetUniqueStatement(
565       db_fields::kGetAllRowsFromGarbageCollectionTableOp));
566   if (!smt.is_valid())
567     return false;
568
569   while (smt.Step()) {
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.";
575       return false;
576     }
577
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.";
583       return false;
584     }
585   }
586
587   return transaction.Commit();
588 }
589
590 }  // namespace application
591 }  // namespace xwalk