Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / password_manager / password_store_win.cc
blob7ff08bf8f864a2ed434d399cc5496868f4cfdc4b
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
3 // found in the LICENSE file.
5 #include "chrome/browser/password_manager/password_store_win.h"
7 #include <map>
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/profiler/scoped_profile.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "components/os_crypt/ie7_password_win.h"
16 #include "components/password_manager/core/browser/password_manager.h"
17 #include "components/password_manager/core/browser/webdata/password_web_data_service_win.h"
18 #include "content/public/browser/browser_thread.h"
20 using autofill::PasswordForm;
21 using content::BrowserThread;
22 using password_manager::PasswordStoreDefault;
24 // Handles requests to PasswordWebDataService.
25 class PasswordStoreWin::DBHandler : public WebDataServiceConsumer {
26 public:
27 DBHandler(PasswordWebDataService* web_data_service,
28 PasswordStoreWin* password_store)
29 : web_data_service_(web_data_service),
30 password_store_(password_store) {
33 ~DBHandler();
35 // Requests the IE7 login for |form|. This is async. |callback_runner| will be
36 // run when complete.
37 void GetIE7Login(
38 const PasswordForm& form,
39 const PasswordStoreWin::ConsumerCallbackRunner& callback_runner);
41 private:
42 struct RequestInfo {
43 RequestInfo() {}
45 RequestInfo(PasswordForm* request_form,
46 const PasswordStoreWin::ConsumerCallbackRunner& runner)
47 : form(request_form),
48 callback_runner(runner) {}
50 PasswordForm* form;
51 PasswordStoreWin::ConsumerCallbackRunner callback_runner;
54 // Holds info associated with in-flight GetIE7Login requests.
55 typedef std::map<PasswordWebDataService::Handle, RequestInfo>
56 PendingRequestMap;
58 // Gets logins from IE7 if no others are found. Also copies them into
59 // Chrome's WebDatabase so we don't need to look next time.
60 std::vector<autofill::PasswordForm*> GetIE7Results(
61 const WDTypedResult* result,
62 const PasswordForm& form);
64 // WebDataServiceConsumer implementation.
65 virtual void OnWebDataServiceRequestDone(
66 PasswordWebDataService::Handle handle,
67 const WDTypedResult* result) override;
69 scoped_refptr<PasswordWebDataService> web_data_service_;
71 // This creates a cycle between us and PasswordStore. The cycle is broken
72 // from PasswordStoreWin::Shutdown, which deletes us.
73 scoped_refptr<PasswordStoreWin> password_store_;
75 PendingRequestMap pending_requests_;
77 DISALLOW_COPY_AND_ASSIGN(DBHandler);
80 PasswordStoreWin::DBHandler::~DBHandler() {
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
82 for (PendingRequestMap::const_iterator i = pending_requests_.begin();
83 i != pending_requests_.end();
84 ++i) {
85 web_data_service_->CancelRequest(i->first);
86 delete i->second.form;
90 void PasswordStoreWin::DBHandler::GetIE7Login(
91 const PasswordForm& form,
92 const PasswordStoreWin::ConsumerCallbackRunner& callback_runner) {
93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
94 IE7PasswordInfo info;
95 info.url_hash =
96 ie7_password::GetUrlHash(base::UTF8ToWide(form.origin.spec()));
97 PasswordWebDataService::Handle handle =
98 web_data_service_->GetIE7Login(info, this);
99 pending_requests_[handle] =
100 RequestInfo(new PasswordForm(form), callback_runner);
103 std::vector<PasswordForm*> PasswordStoreWin::DBHandler::GetIE7Results(
104 const WDTypedResult *result,
105 const PasswordForm& form) {
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
107 std::vector<PasswordForm*> matching_forms;
109 const WDResult<IE7PasswordInfo>* r =
110 static_cast<const WDResult<IE7PasswordInfo>*>(result);
111 IE7PasswordInfo info = r->GetValue();
113 if (!info.encrypted_data.empty()) {
114 // We got a result.
115 // Delete the entry. If it's good we will add it to the real saved password
116 // table.
117 web_data_service_->RemoveIE7Login(info);
118 std::vector<ie7_password::DecryptedCredentials> credentials;
119 std::wstring url = base::ASCIIToWide(form.origin.spec());
120 if (ie7_password::DecryptPasswords(url,
121 info.encrypted_data,
122 &credentials)) {
123 for (size_t i = 0; i < credentials.size(); ++i) {
124 PasswordForm* autofill = new PasswordForm();
125 autofill->username_value = credentials[i].username;
126 autofill->password_value = credentials[i].password;
127 autofill->signon_realm = form.signon_realm;
128 autofill->origin = form.origin;
129 autofill->preferred = true;
130 autofill->ssl_valid = form.origin.SchemeIsSecure();
131 autofill->date_created = info.date_created;
133 matching_forms.push_back(autofill);
134 // Add this PasswordForm to the saved password table. We're on the DB
135 // thread already, so we use AddLoginImpl.
136 password_store_->AddLoginImpl(*autofill);
140 return matching_forms;
143 void PasswordStoreWin::DBHandler::OnWebDataServiceRequestDone(
144 PasswordWebDataService::Handle handle,
145 const WDTypedResult* result) {
146 // TODO(vadimt): Remove ScopedProfile below once crbug.com/422460 is fixed.
147 tracked_objects::ScopedProfile tracking_profile(
148 FROM_HERE_WITH_EXPLICIT_FUNCTION(
149 "422460 PasswordStoreWin::DBHandler::OnWebDataServiceRequestDone"));
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
153 PendingRequestMap::iterator i = pending_requests_.find(handle);
154 DCHECK(i != pending_requests_.end());
156 scoped_ptr<PasswordForm> form(i->second.form);
157 PasswordStoreWin::ConsumerCallbackRunner callback_runner(
158 i->second.callback_runner);
159 pending_requests_.erase(i);
161 if (!result) {
162 // The WDS returns NULL if it is shutting down. Run callback with empty
163 // result.
164 callback_runner.Run(std::vector<autofill::PasswordForm*>());
165 return;
168 DCHECK_EQ(PASSWORD_IE7_RESULT, result->GetType());
169 std::vector<autofill::PasswordForm*> matched_forms =
170 GetIE7Results(result, *form);
172 callback_runner.Run(matched_forms);
175 PasswordStoreWin::PasswordStoreWin(
176 scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
177 scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
178 password_manager::LoginDatabase* login_database,
179 PasswordWebDataService* web_data_service)
180 : PasswordStoreDefault(main_thread_runner,
181 db_thread_runner,
182 login_database) {
183 db_handler_.reset(new DBHandler(web_data_service, this));
186 PasswordStoreWin::~PasswordStoreWin() {
189 void PasswordStoreWin::ShutdownOnDBThread() {
190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
191 db_handler_.reset();
194 void PasswordStoreWin::Shutdown() {
195 BrowserThread::PostTask(
196 BrowserThread::DB, FROM_HERE,
197 base::Bind(&PasswordStoreWin::ShutdownOnDBThread, this));
198 PasswordStoreDefault::Shutdown();
201 void PasswordStoreWin::GetIE7LoginIfNecessary(
202 const PasswordForm& form,
203 const ConsumerCallbackRunner& callback_runner,
204 const std::vector<autofill::PasswordForm*>& matched_forms) {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
206 if (matched_forms.empty() && db_handler_.get()) {
207 db_handler_->GetIE7Login(form, callback_runner);
208 } else {
209 // No need to get IE7 login.
210 callback_runner.Run(matched_forms);
214 void PasswordStoreWin::GetLoginsImpl(
215 const PasswordForm& form,
216 AuthorizationPromptPolicy prompt_policy,
217 const ConsumerCallbackRunner& callback_runner) {
218 ConsumerCallbackRunner get_ie7_login =
219 base::Bind(&PasswordStoreWin::GetIE7LoginIfNecessary,
220 this, form, callback_runner);
221 PasswordStoreDefault::GetLoginsImpl(form, prompt_policy, get_ie7_login);