Upstream version 8.36.156.0
[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 kPermissionSeparator = '^';
29
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;
33
34 namespace {
35
36 const std::string StoredPermissionStr[] = {
37     "ALLOW",
38     "DENY",
39     "PROMPT",
40 };
41
42 const base::FilePath::CharType kApplicationDataDirName[] =
43     FILE_PATH_LITERAL("Storage/ext");
44
45 std::string ToString(StoredPermission permission) {
46   if (permission == UNDEFINED_STORED_PERM)
47     return std::string("");
48   return StoredPermissionStr[permission];
49 }
50
51 StoredPermission ToPermission(const std::string& str) {
52   unsigned int i;
53   for (i = 0; i < UNDEFINED_STORED_PERM; ++i) {
54     if (str == StoredPermissionStr[i])
55       break;
56   }
57   return static_cast<StoredPermission>(i);
58 }
59
60 inline const base::FilePath GetDBPath(const base::FilePath& path) {
61   return path.Append(ApplicationStorageImpl::kDBFileName);
62 }
63
64 // Initializes the applications table, returning true on success.
65 bool InitApplicationsTable(sql::Connection* db) {
66   sql::Transaction transaction(db);
67   transaction.Begin();
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))
71       return false;
72   }
73   return transaction.Commit();
74 }
75
76 // Permissions are stored like "bluetooth^ALLOW;calendar^DENY;contacts^ALLOW"
77 std::string ToString(StoredPermissionMap permissions) {
78   std::string str;
79   StoredPermissionMap::iterator iter;
80   for (iter = permissions.begin(); iter != permissions.end(); ++iter) {
81     if (!str.empty())
82       str += ";";
83     str += (iter->first + kPermissionSeparator + ToString(iter->second));
84   }
85   return str;
86 }
87
88 StoredPermissionMap ToPermissionMap(const std::string& str) {
89   StoredPermissionMap map;
90   std::vector<std::string> vec;
91   base::SplitString(str, ';', &vec);
92   if (!vec.empty()) {
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?";
99         map.clear();
100         break;
101       }
102       map[perm_item[0]] = ToPermission(perm_item[1]);
103     }
104   }
105   return map;
106 }
107
108 bool InitPermissionsTable(sql::Connection* db) {
109   sql::Transaction transaction(db);
110   transaction.Begin();
111   if (!db->DoesTableExist(db_fields::kPermissionTableName)) {
112     if (!db->Execute(db_fields::kCreatePermissionTableOp))
113      return false;
114   }
115   return transaction.Commit();
116 }
117
118
119 bool InitGarbageCollectionTable(sql::Connection* db) {
120   sql::Transaction transaction(db);
121   transaction.Begin();
122   if (!db->DoesTableExist(db_fields::kGarbageCollectionTableName)) {
123     if (!db->Execute(db_fields::kCreateGarbageCollectionTableOp) ||
124         !db->Execute(db_fields::kCreateGarbageCollectionTriggersOp))
125      return false;
126   }
127
128   return transaction.Commit();
129 }
130
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;
136 }
137
138 base::FilePath GetAppDataPath(
139     const base::FilePath& base_path, const std::string& app_id) {
140   return base_path.Append(kApplicationDataDirName).Append(app_id);
141 }
142
143 }  // namespace
144
145 ApplicationStorageImpl::ApplicationStorageImpl(const base::FilePath& path)
146     : data_path_(path),
147       db_initialized_(false) {
148   // Ensure the parent directory for database file is created before reading
149   // from it.
150   if (!base::PathExists(path) && !base::CreateDirectory(path))
151     return;
152 }
153
154 bool ApplicationStorageImpl::UpgradeToVersion1(const base::FilePath& v0_file) {
155   JSONFileValueSerializer serializer(v0_file);
156   int error_code;
157   std::string error;
158   base::Value* old_db = serializer.Deserialize(&error_code, &error);
159   if (!old_db) {
160     LOG(ERROR) << "Unable to read applications information from JSON DB, "
161                   "the error message is: "
162                << error;
163     return false;
164   }
165
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);
173     std::string path;
174     value->GetString("path", &path);
175     std::string error;
176     scoped_refptr<ApplicationData> application =
177         ApplicationData::Create(base::FilePath::FromUTF8Unsafe(path),
178                                 Manifest::INTERNAL,
179                                 *manifest,
180                                 it.key(),
181                                 &error);
182     if (!application) {
183       LOG(ERROR) << "Unable to migrate the information to Version 1: " << error;
184       return false;
185     }
186
187     double install_time;
188     value->GetDouble("install_time", &install_time);
189     if (!AddApplication(application, base::Time::FromDoubleT(install_time)))
190       return false;
191   }
192   meta_table_.SetVersionNumber(1);
193
194   return true;
195 }
196
197 ApplicationStorageImpl::~ApplicationStorageImpl() {
198 }
199
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.";
206     return false;
207   }
208   sqlite_db->Preload();
209
210   if (!meta_table_.Init(sqlite_db.get(), kVersionNumber, kVersionNumber) ||
211       meta_table_.GetVersionNumber() != kVersionNumber) {
212     LOG(ERROR) << "Unable to init the META table.";
213     return false;
214   }
215
216   if (!InitApplicationsTable(sqlite_db.get())) {
217     LOG(ERROR) << "Unable to open applications table.";
218     return false;
219   }
220
221   if (!InitPermissionsTable(sqlite_db.get())) {
222     LOG(ERROR) << "Unable to open registered permissions table.";
223     return false;
224   }
225
226   if (!InitGarbageCollectionTable(sqlite_db.get())) {
227     LOG(ERROR) << "Unable to open garbage collection table.";
228     return false;
229   }
230
231   if (!sqlite_db->Execute("PRAGMA foreign_keys=ON")) {
232     LOG(ERROR) << "Unable to enforce foreign key contraints.";
233     return false;
234   }
235
236   sqlite_db_.reset(sqlite_db.release());
237
238   db_initialized_ = (sqlite_db_ && sqlite_db_->is_open());
239
240   base::FilePath v0_file = data_path_.Append(
241       FILE_PATH_LITERAL("applications_db"));
242   if (base::PathExists(v0_file) &&
243       !does_db_exist) {
244     if (!UpgradeToVersion1(v0_file)) {
245       LOG(ERROR) << "Unable to migrate database from JSON format to SQLite.";
246       return false;
247     }
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.";
252       return false;
253     }
254   }
255
256   db_initialized_ = GetInstalledApplications(applications);
257
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.";
262
263   return db_initialized_;
264 }
265
266 bool ApplicationStorageImpl::GetInstalledApplications(
267     ApplicationData::ApplicationDataMap& applications) {
268   if (!db_initialized_) {
269     LOG(ERROR) << "The database haven't initilized.";
270     return false;
271   }
272
273   sql::Statement smt(sqlite_db_->GetUniqueStatement(
274       db_fields::kGetAllRowsFromAppTableOp));
275   if (!smt.is_valid())
276     return false;
277
278   std::string error_msg;
279   while (smt.Step()) {
280     std::string id = smt.ColumnString(0);
281
282     int error_code;
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)));
288
289     if (!manifest) {
290       LOG(ERROR) << "An error occured when deserializing the manifest, "
291                     "the error message is: "
292                  << error_msg;
293       return false;
294     }
295     std::string path = smt.ColumnString(2);
296     double install_time = smt.ColumnDouble(3);
297
298     std::string error;
299     scoped_refptr<ApplicationData> application =
300         ApplicationData::Create(
301             base::FilePath::FromUTF8Unsafe(path),
302             Manifest::INTERNAL,
303             *manifest,
304             id,
305             &error);
306     if (!application) {
307       LOG(ERROR) << "Load appliation error: " << error;
308       return false;
309     }
310
311     application->install_time_ = base::Time::FromDoubleT(install_time);
312
313     application->permission_map_ = ToPermissionMap(smt.ColumnString(5));
314
315     if (!Insert(application, applications)) {
316       LOG(ERROR) << "An error occurred while"
317                     "initializing the application cache data.";
318       return false;
319     }
320   }
321
322   return true;
323 }
324
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.";
329     return false;
330   }
331
332   return (SetApplicationValue(
333       application, install_time, db_fields::kSetApplicationWithBindOp) &&
334           SetPermissions(application->ID(), application->permission_map_));
335 }
336
337 bool ApplicationStorageImpl::UpdateApplication(
338     ApplicationData* application, const base::Time& install_time) {
339   if (!db_initialized_) {
340     LOG(ERROR) << "The database haven't initialized.";
341     return false;
342   }
343
344   if (SetApplicationValue(
345           application, install_time, db_fields::kUpdateApplicationWithBindOp) &&
346       UpdatePermissions(application->ID(), application->permission_map_)) {
347     application->is_dirty_ = false;
348     return true;
349   }
350
351   return false;
352 }
353
354 bool ApplicationStorageImpl::RemoveApplication(const std::string& id) {
355   if (!db_initialized_) {
356     LOG(ERROR) << "The database haven't initialized.";
357     return false;
358   }
359
360   sql::Transaction transaction(sqlite_db_.get());
361   if (!transaction.Begin())
362     return false;
363
364   sql::Statement smt(sqlite_db_->GetUniqueStatement(
365       db_fields::kDeleteApplicationWithBindOp));
366   smt.BindString(0, id);
367   if (!smt.Run()) {
368     LOG(ERROR) << "Could not delete application "
369                   "information from DB.";
370     return false;
371   }
372
373   return transaction.Commit();
374 }
375
376 bool ApplicationStorageImpl::SetApplicationValue(
377     const ApplicationData* application,
378     const base::Time& install_time,
379     const std::string& operation) {
380   if (!application) {
381     LOG(ERROR) << "A value is needed when inserting/updating in DB.";
382     return false;
383   }
384
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.";
389     return false;
390   }
391
392   sql::Transaction transaction(sqlite_db_.get());
393   if (!transaction.Begin())
394     return false;
395
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.";
399     return false;
400   }
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());
405   if (!smt.Run()) {
406     LOG(ERROR) << "An error occured when inserting/updating "
407                   "application info in DB.";
408     return false;
409   }
410
411   return transaction.Commit();
412 }
413
414 bool ApplicationStorageImpl::SetPermissions(const std::string& id,
415     const StoredPermissionMap& permissions) {
416   if (!db_initialized_) {
417     LOG(ERROR) << "Database is not initialized.";
418     return false;
419   }
420   return SetPermissionsValue(id, permissions,
421       db_fields::kInsertPermissionsWithBindOp);
422 }
423
424 bool ApplicationStorageImpl::UpdatePermissions(const std::string& id,
425     const StoredPermissionMap& permissions) {
426   if (!db_initialized_) {
427     LOG(ERROR) << "Database is not initialized.";
428     return false;
429   }
430   if (permissions.empty())
431     return RevokePermissions(id);
432
433   return SetPermissionsValue(id, permissions,
434       db_fields::kUpdatePermissionsWithBindOp);
435 }
436
437 bool ApplicationStorageImpl::RevokePermissions(const std::string& id) {
438   sql::Transaction transaction(sqlite_db_.get());
439   if (!transaction.Begin())
440     return false;
441
442   sql::Statement statement(sqlite_db_->GetUniqueStatement(
443       db_fields::kDeletePermissionsWithBindOp));
444   statement.BindString(0, id);
445
446   if (!statement.Run()) {
447     LOG(ERROR) <<
448         "An error occurred while removing permissions.";
449     return false;
450   }
451   return transaction.Commit();
452 }
453
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);
460
461   if (!transaction.Begin())
462     return false;
463
464   sql::Statement statement(sqlite_db_->GetUniqueStatement(
465       operation.c_str()));
466   statement.BindString(0, permission_str);
467   statement.BindString(1, id);
468   if (!statement.Run()) {
469     LOG(ERROR) <<
470         "An error occurred while inserting permissions.";
471     return false;
472   }
473   return transaction.Commit();
474 }
475
476 bool ApplicationStorageImpl::CollectGarbageApplications() {
477   sql::Transaction transaction(sqlite_db_.get());
478   if (!transaction.Begin())
479     return false;
480
481   sql::Statement smt(sqlite_db_->GetUniqueStatement(
482       db_fields::kGetAllRowsFromGarbageCollectionTableOp));
483   if (!smt.is_valid())
484     return false;
485
486   while (smt.Step()) {
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.";
492       return false;
493     }
494
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.";
500       return false;
501     }
502   }
503
504   return transaction.Commit();
505 }
506
507 }  // namespace application
508 }  // namespace xwalk