1 // Copyright 2016 The Chromium Authors. 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 #ifndef COMPONENTS_SERVICES_STORAGE_DOM_STORAGE_LOCAL_STORAGE_IMPL_H_
6 #define COMPONENTS_SERVICES_STORAGE_DOM_STORAGE_LOCAL_STORAGE_IMPL_H_
7 
8 #include <stdint.h>
9 #include <map>
10 #include <memory>
11 #include <set>
12 #include <string>
13 #include <vector>
14 
15 #include "base/callback_forward.h"
16 #include "base/files/file_path.h"
17 #include "base/memory/ref_counted.h"
18 #include "base/sequenced_task_runner.h"
19 #include "base/threading/sequence_bound.h"
20 #include "base/trace_event/memory_allocator_dump.h"
21 #include "base/trace_event/memory_dump_provider.h"
22 #include "components/services/storage/dom_storage/async_dom_storage_database.h"
23 #include "components/services/storage/dom_storage/dom_storage_database.h"
24 #include "components/services/storage/public/mojom/local_storage_control.mojom.h"
25 #include "mojo/public/cpp/bindings/pending_receiver.h"
26 #include "mojo/public/cpp/bindings/receiver.h"
27 #include "mojo/public/cpp/bindings/remote.h"
28 #include "third_party/blink/public/mojom/dom_storage/storage_area.mojom.h"
29 #include "url/origin.h"
30 
31 namespace storage {
32 
33 // The Local Storage implementation. An instance of this class exists for each
34 // storage partition using Local Storage, managing storage for all origins
35 // within the partition.
36 class LocalStorageImpl : public base::trace_event::MemoryDumpProvider,
37                          public mojom::LocalStorageControl {
38  public:
39   static base::FilePath LegacyDatabaseFileNameFromOrigin(
40       const url::Origin& origin);
41   static url::Origin OriginFromLegacyDatabaseFileName(
42       const base::FilePath& file_name);
43 
44   // Constructs a Local Storage implementation which will create its root
45   // "Local Storage" directory in |storage_root| if non-empty. |task_runner|
46   // run tasks on the same sequence as the one which constructs this object.
47   // |legacy_task_runner| must support blocking operations and its tasks must
48   // be able to block shutdown. If valid, |receiver| will be bound to this
49   // object to allow for remote control via the LocalStorageControl interface.
50   LocalStorageImpl(const base::FilePath& storage_root,
51                    scoped_refptr<base::SequencedTaskRunner> task_runner,
52                    scoped_refptr<base::SequencedTaskRunner> legacy_task_runner,
53                    mojo::PendingReceiver<mojom::LocalStorageControl> receiver);
54 
55   void FlushOriginForTesting(const url::Origin& origin);
56 
57   // Used by content settings to alter the behavior around
58   // what data to keep and what data to discard at shutdown.
59   // The policy is not so straight forward to describe, see
60   // the implementation for details.
SetForceKeepSessionState()61   void SetForceKeepSessionState() { force_keep_session_state_ = true; }
62 
63   // Called when the owning BrowserContext is ending.
64   // Schedules the commit of any unsaved changes and will delete
65   // and keep data on disk per the content settings and special storage
66   // policies.
67   void ShutdownAndDelete();
68 
69   // Clears unused storage areas, when thresholds are reached.
70   void PurgeUnusedAreasIfNeeded();
71 
72   // mojom::LocalStorageControl implementation:
73   void BindStorageArea(
74       const url::Origin& origin,
75       mojo::PendingReceiver<blink::mojom::StorageArea> receiver) override;
76   void GetUsage(GetUsageCallback callback) override;
77   void DeleteStorage(const url::Origin& origin,
78                      DeleteStorageCallback callback) override;
79   void CleanUpStorage(CleanUpStorageCallback callback) override;
80   void Flush(FlushCallback callback) override;
81   void PurgeMemory() override;
82   void ApplyPolicyUpdates(
83       std::vector<mojom::LocalStoragePolicyUpdatePtr> policy_updates) override;
84   void ForceKeepSessionState() override;
85 
86   // base::trace_event::MemoryDumpProvider implementation.
87   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
88                     base::trace_event::ProcessMemoryDump* pmd) override;
89 
90   // Converts a string from the old storage format to the new storage format.
91   static std::vector<uint8_t> MigrateString(const base::string16& input);
92 
93   // Access the underlying DomStorageDatabase. May be null if the database is
94   // not yet open.
GetDatabaseForTesting()95   const base::SequenceBound<DomStorageDatabase>& GetDatabaseForTesting() const {
96     return database_->database();
97   }
98 
99   // Wait for the database to be opened, or for opening to fail. If the database
100   // is already opened, |callback| is invoked immediately.
101   void SetDatabaseOpenCallbackForTesting(base::OnceClosure callback);
102 
103  private:
104   friend class DOMStorageBrowserTest;
105 
106   class StorageAreaHolder;
107 
108   ~LocalStorageImpl() override;
109 
110   // Runs |callback| immediately if already connected to a database, otherwise
111   // delays running |callback| untill after a connection has been established.
112   // Initiates connecting to the database if no connection is in progres yet.
113   void RunWhenConnected(base::OnceClosure callback);
114 
115   // Part of our asynchronous directory opening called from RunWhenConnected().
116   void InitiateConnection(bool in_memory_only = false);
117   void OnDatabaseOpened(leveldb::Status status);
118   void OnGotDatabaseVersion(leveldb::Status status,
119                             const std::vector<uint8_t>& value);
120   void OnConnectionFinished();
121   void DeleteAndRecreateDatabase(const char* histogram_name);
122   void OnDBDestroyed(bool recreate_in_memory, leveldb::Status status);
123 
124   StorageAreaHolder* GetOrCreateStorageArea(const url::Origin& origin);
125 
126   // The (possibly delayed) implementation of GetUsage(). Can be called directly
127   // from that function, or through |on_database_open_callbacks_|.
128   void RetrieveStorageUsage(GetUsageCallback callback);
129   void OnGotMetaData(GetUsageCallback callback,
130                      std::vector<DomStorageDatabase::KeyValuePair> data);
131 
132   void OnGotStorageUsageForShutdown(
133       std::vector<mojom::LocalStorageUsageInfoPtr> usage);
134   void OnShutdownComplete(leveldb::Status status);
135 
136   void GetStatistics(size_t* total_cache_size, size_t* unused_area_count);
137   void OnCommitResult(leveldb::Status status);
138 
139   // These values are written to logs.  New enum values can be added, but
140   // existing enums must never be renumbered or deleted and reused.
141   enum class OpenResult {
142     DIRECTORY_OPEN_FAILED = 0,
143     DATABASE_OPEN_FAILED = 1,
144     INVALID_VERSION = 2,
145     VERSION_READ_ERROR = 3,
146     SUCCESS = 4,
147     MAX
148   };
149 
150   void LogDatabaseOpenResult(OpenResult result);
151 
152   const base::FilePath directory_;
153 
154   enum ConnectionState {
155     NO_CONNECTION,
156     CONNECTION_IN_PROGRESS,
157     CONNECTION_FINISHED,
158     CONNECTION_SHUTDOWN
159   } connection_state_ = NO_CONNECTION;
160   bool database_initialized_ = false;
161 
162   bool force_keep_session_state_ = false;
163 
164   const scoped_refptr<base::SequencedTaskRunner> leveldb_task_runner_;
165 
166   base::trace_event::MemoryAllocatorDumpGuid memory_dump_id_;
167 
168   std::unique_ptr<AsyncDomStorageDatabase> database_;
169   bool tried_to_recreate_during_open_ = false;
170   bool in_memory_ = false;
171 
172   std::vector<base::OnceClosure> on_database_opened_callbacks_;
173 
174   // Maps between an origin and its prefixed LevelDB view.
175   std::map<url::Origin, std::unique_ptr<StorageAreaHolder>> areas_;
176 
177   // Used to access old data for migration.
178   scoped_refptr<base::SequencedTaskRunner> legacy_task_runner_;
179 
180   bool is_low_end_device_;
181   // Counts consecutive commit errors. If this number reaches a threshold, the
182   // whole database is thrown away.
183   int commit_error_count_ = 0;
184   bool tried_to_recover_from_commit_errors_ = false;
185 
186   // The set of (origin) URLs whose storage should be cleared on shutdown.
187   std::set<GURL> origins_to_purge_on_shutdown_;
188 
189   // Name of an extra histogram to log open results to, if not null.
190   const char* open_result_histogram_ = nullptr;
191 
192   mojo::Receiver<mojom::LocalStorageControl> control_receiver_{this};
193 
194   base::WeakPtrFactory<LocalStorageImpl> weak_ptr_factory_{this};
195 };
196 
197 }  // namespace storage
198 
199 #endif  // COMPONENTS_SERVICES_STORAGE_DOM_STORAGE_LOCAL_STORAGE_IMPL_H_
200