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 |