Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "sql/connection.h" | 5 #include "sql/connection.h" |
| 6 | 6 |
| 7 #include <string.h> | 7 #include <string.h> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/json/json_file_value_serializer.h" | |
| 12 #include "base/lazy_instance.h" | 13 #include "base/lazy_instance.h" |
| 13 #include "base/logging.h" | 14 #include "base/logging.h" |
| 14 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
| 15 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" |
| 16 #include "base/metrics/sparse_histogram.h" | 17 #include "base/metrics/sparse_histogram.h" |
| 17 #include "base/strings/string_split.h" | 18 #include "base/strings/string_split.h" |
| 18 #include "base/strings/string_util.h" | 19 #include "base/strings/string_util.h" |
| 19 #include "base/strings/stringprintf.h" | 20 #include "base/strings/stringprintf.h" |
| 20 #include "base/strings/utf_string_conversions.h" | 21 #include "base/strings/utf_string_conversions.h" |
| 21 #include "base/synchronization/lock.h" | 22 #include "base/synchronization/lock.h" |
| (...skipping 1504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1526 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF"; | 1527 const char kNoWritableSchema[] = "PRAGMA writable_schema = OFF"; |
| 1527 ignore_result(Execute(kNoWritableSchema)); | 1528 ignore_result(Execute(kNoWritableSchema)); |
| 1528 | 1529 |
| 1529 return ret; | 1530 return ret; |
| 1530 } | 1531 } |
| 1531 | 1532 |
| 1532 base::TimeTicks TimeSource::Now() { | 1533 base::TimeTicks TimeSource::Now() { |
| 1533 return base::TimeTicks::Now(); | 1534 return base::TimeTicks::Now(); |
| 1534 } | 1535 } |
| 1535 | 1536 |
| 1537 base::FilePath Connection::DbPath() const { | |
| 1538 if (!is_open()) | |
| 1539 return base::FilePath(); | |
| 1540 | |
| 1541 const char* path = sqlite3_db_filename(db_, "main"); | |
| 1542 const base::StringPiece db_path(path); | |
| 1543 #if defined(OS_WIN) | |
| 1544 return base::FilePath(base::UTF8ToWide(db_path)); | |
| 1545 #elif defined(OS_POSIX) | |
| 1546 return base::FilePath(db_path); | |
| 1547 #else | |
| 1548 NOTREACHED(); | |
| 1549 return base::FilePath(); | |
| 1550 #endif | |
| 1551 } | |
| 1552 | |
| 1553 // Decide whether to upload based on a shared breadcrumb file in the database | |
| 1554 // directory. The breadcrumb file records whether a past upload has occurred, | |
| 1555 // and also acts as a probe to determine if basic filesystem actions work in the | |
| 1556 // profile directory. | |
| 1557 // | |
| 1558 // Top level is a dictionary storing a version number, and an array of databases | |
| 1559 // which have been dumped. | |
| 1560 bool Connection::ShouldUploadDiagnosticDump() const { | |
|
pkotwicz
2015/10/15 18:02:29
Nit: Can you please move this function so that it
Scott Hess - ex-Googler
2015/10/15 21:12:20
I can put it after OnMemoryDump(), but the functio
| |
| 1561 static const char* kVersionKey = "version"; | |
| 1562 static const char* kDiagnosticDumpsKey = "DiagnosticDumps"; | |
| 1563 static int kVersion = 1; | |
| 1564 | |
| 1565 AssertIOAllowed(); | |
| 1566 | |
| 1567 if (histogram_tag_.empty()) | |
| 1568 return false; | |
| 1569 | |
| 1570 if (!is_open()) | |
| 1571 return false; | |
| 1572 | |
| 1573 if (in_memory_) | |
| 1574 return false; | |
| 1575 | |
| 1576 const base::FilePath db_path = DbPath(); | |
| 1577 if (db_path.empty()) | |
| 1578 return false; | |
| 1579 | |
| 1580 // Put the collection of diagnostic data next to the databases. In most | |
| 1581 // cases, this is the profile directory, but safe-browsing stores a Cookies | |
| 1582 // file in the directory above the profile directory. | |
| 1583 base::FilePath breadcrumb_path( | |
| 1584 db_path.DirName().Append(FILE_PATH_LITERAL("sqlite-diag"))); | |
| 1585 | |
| 1586 // Lock against multiple updates to the diagnostics file. This code should | |
| 1587 // seldom be called in the first place, and when called it should seldom be | |
| 1588 // called for multiple databases, and when called for multiple databases there | |
| 1589 // is _probably_ something systemic wrong with the user's system. So the lock | |
| 1590 // should never be contended, but when it is the database experience is | |
| 1591 // already bad. | |
| 1592 base::AutoLock lock(g_sqlite_init_lock.Get()); | |
| 1593 | |
| 1594 scoped_ptr<base::Value> root; | |
| 1595 if (!base::PathExists(breadcrumb_path)) { | |
| 1596 scoped_ptr<base::DictionaryValue> root_dict(new base::DictionaryValue()); | |
| 1597 root_dict->SetInteger(kVersionKey, kVersion); | |
| 1598 | |
| 1599 scoped_ptr<base::ListValue> dumps(new base::ListValue); | |
| 1600 dumps->AppendString(histogram_tag_); | |
| 1601 root_dict->Set(kDiagnosticDumpsKey, dumps.Pass()); | |
| 1602 | |
| 1603 root = root_dict.Pass(); | |
| 1604 } else { | |
| 1605 // Failure to read a valid dictionary implies that something is going wrong | |
| 1606 // on the system. | |
| 1607 JSONFileValueDeserializer deserializer(breadcrumb_path); | |
| 1608 scoped_ptr<base::Value> read_root(deserializer.Deserialize(NULL, NULL)); | |
|
pkotwicz
2015/10/15 18:02:30
Nit: NULL -> nullptr
Scott Hess - ex-Googler
2015/10/15 21:12:21
Acknowledged.
| |
| 1609 if (!read_root.get()) | |
| 1610 return false; | |
| 1611 scoped_ptr<base::DictionaryValue> root_dict = | |
| 1612 base::DictionaryValue::From(read_root.Pass()); | |
| 1613 if (!root_dict) | |
| 1614 return false; | |
| 1615 | |
| 1616 // Don't upload if the version is missing or newer. | |
| 1617 int version = 0; | |
| 1618 if (!root_dict->GetInteger(kVersionKey, &version) || version > kVersion) | |
| 1619 return false; | |
| 1620 | |
| 1621 base::ListValue* dumps = NULL; | |
|
pkotwicz
2015/10/15 18:02:29
Nit: NULL -> nullptr
Scott Hess - ex-Googler
2015/10/15 21:12:21
Acknowledged.
| |
| 1622 if (!root_dict->GetList(kDiagnosticDumpsKey, &dumps)) | |
| 1623 return false; | |
| 1624 | |
| 1625 const size_t size = dumps->GetSize(); | |
| 1626 for (size_t i = 0; i < size; ++i) { | |
| 1627 std::string s; | |
| 1628 | |
| 1629 // Don't upload if the value isn't a string, or indicates a prior upload. | |
| 1630 if (!dumps->GetString(i, &s) || s == histogram_tag_) | |
| 1631 return false; | |
| 1632 } | |
| 1633 | |
| 1634 // Record intention to proceed with upload. | |
| 1635 dumps->AppendString(histogram_tag_); | |
| 1636 root = root_dict.Pass(); | |
| 1637 } | |
| 1638 | |
| 1639 const base::FilePath breadcrumb_new = | |
| 1640 breadcrumb_path.AddExtension(FILE_PATH_LITERAL("new")); | |
|
pkotwicz
2015/10/15 18:02:29
Should we use base::CreateTemporaryFile() instead?
Scott Hess - ex-Googler
2015/10/15 21:12:20
I'll assume you intended CreateTemporaryFileInDir(
pkotwicz
2015/10/15 23:31:06
Fair enough
| |
| 1641 base::DeleteFile(breadcrumb_new, false); | |
| 1642 | |
| 1643 // No upload if the breadcrumb file cannot be updated. | |
| 1644 // TODO(shess): Consider ImportantFileWriter::WriteFileAtomically() to land | |
| 1645 // the data on disk. For now, losing the data is not a big problem, so the | |
| 1646 // sync overhead would probably not be worth it. | |
| 1647 JSONFileValueSerializer serializer(breadcrumb_new); | |
| 1648 if (!serializer.Serialize(*root)) | |
| 1649 return false; | |
| 1650 if (!base::PathExists(breadcrumb_new)) | |
| 1651 return false; | |
| 1652 if (!base::ReplaceFile(breadcrumb_new, breadcrumb_path, nullptr)) { | |
| 1653 base::DeleteFile(breadcrumb_new, false); | |
| 1654 return false; | |
| 1655 } | |
| 1656 | |
| 1657 return true; | |
| 1658 } | |
| 1659 | |
| 1536 } // namespace sql | 1660 } // namespace sql |
| OLD | NEW |