Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / android_webview / native / state_serializer.cc
blob5abc929320e989d6d03a19f0e05c5b8b687383d2
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 "android_webview/native/state_serializer.h"
7 #include <string>
9 #include "base/memory/scoped_vector.h"
10 #include "base/pickle.h"
11 #include "base/time.h"
12 #include "content/public/browser/navigation_controller.h"
13 #include "content/public/browser/navigation_entry.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/common/page_state.h"
17 // Reasons for not re-using TabNavigation under chrome/ as of 20121116:
18 // * Android WebView has different requirements for fields to store since
19 // we are the only ones using values like BaseURLForDataURL.
20 // * TabNavigation does unnecessary copying of data, which in Android
21 // WebView case, is undesired since save/restore is called in Android
22 // very frequently.
23 // * TabNavigation is tightly integrated with the rest of chrome session
24 // restore and sync code, and has other purpose in addition to serializing
25 // NavigationEntry.
27 using std::string;
29 namespace android_webview {
31 namespace {
33 // Sanity check value that we are restoring from a valid pickle.
34 // This can potentially used as an actual serialization version number in the
35 // future if we ever decide to support restoring from older versions.
36 const uint32 AW_STATE_VERSION = 20121126;
38 } // namespace
40 bool WriteToPickle(const content::WebContents& web_contents,
41 Pickle* pickle) {
42 DCHECK(pickle);
44 if (!internal::WriteHeaderToPickle(pickle))
45 return false;
47 const content::NavigationController& controller =
48 web_contents.GetController();
49 const int entry_count = controller.GetEntryCount();
50 const int selected_entry = controller.GetCurrentEntryIndex();
51 DCHECK(entry_count >= 0);
52 DCHECK(selected_entry >= -1); // -1 is valid
53 DCHECK(selected_entry < entry_count);
55 if (!pickle->WriteInt(entry_count))
56 return false;
58 if (!pickle->WriteInt(selected_entry))
59 return false;
61 for (int i = 0; i < entry_count; ++i) {
62 if (!internal::WriteNavigationEntryToPickle(*controller.GetEntryAtIndex(i),
63 pickle))
64 return false;
67 // Please update AW_STATE_VERSION if serialization format is changed.
69 return true;
72 bool RestoreFromPickle(PickleIterator* iterator,
73 content::WebContents* web_contents) {
74 DCHECK(iterator);
75 DCHECK(web_contents);
77 if (!internal::RestoreHeaderFromPickle(iterator))
78 return false;
80 int entry_count = -1;
81 int selected_entry = -2; // -1 is a valid value
83 if (!iterator->ReadInt(&entry_count))
84 return false;
86 if (!iterator->ReadInt(&selected_entry))
87 return false;
89 if (entry_count < 0)
90 return false;
91 if (selected_entry < -1)
92 return false;
93 if (selected_entry >= entry_count)
94 return false;
96 ScopedVector<content::NavigationEntry> restored_entries;
97 for (int i = 0; i < entry_count; ++i) {
98 restored_entries.push_back(content::NavigationEntry::Create());
99 if (!internal::RestoreNavigationEntryFromPickle(iterator,
100 restored_entries[i]))
101 return false;
103 restored_entries[i]->SetPageID(i);
106 // |web_contents| takes ownership of these entries after this call.
107 web_contents->GetController().Restore(
108 selected_entry,
109 content::NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
110 &restored_entries.get());
111 DCHECK_EQ(0u, restored_entries.size());
113 return true;
116 namespace internal {
118 bool WriteHeaderToPickle(Pickle* pickle) {
119 return pickle->WriteUInt32(AW_STATE_VERSION);
122 bool RestoreHeaderFromPickle(PickleIterator* iterator) {
123 uint32 state_version = -1;
124 if (!iterator->ReadUInt32(&state_version))
125 return false;
127 if (AW_STATE_VERSION != state_version)
128 return false;
130 return true;
133 bool WriteNavigationEntryToPickle(const content::NavigationEntry& entry,
134 Pickle* pickle) {
135 if (!pickle->WriteString(entry.GetURL().spec()))
136 return false;
138 if (!pickle->WriteString(entry.GetVirtualURL().spec()))
139 return false;
141 const content::Referrer& referrer = entry.GetReferrer();
142 if (!pickle->WriteString(referrer.url.spec()))
143 return false;
144 if (!pickle->WriteInt(static_cast<int>(referrer.policy)))
145 return false;
147 if (!pickle->WriteString16(entry.GetTitle()))
148 return false;
150 if (!pickle->WriteString(entry.GetPageState().ToEncodedData()))
151 return false;
153 if (!pickle->WriteBool(static_cast<int>(entry.GetHasPostData())))
154 return false;
156 if (!pickle->WriteString(entry.GetOriginalRequestURL().spec()))
157 return false;
159 if (!pickle->WriteString(entry.GetBaseURLForDataURL().spec()))
160 return false;
162 if (!pickle->WriteBool(static_cast<int>(entry.GetIsOverridingUserAgent())))
163 return false;
165 if (!pickle->WriteInt64(entry.GetTimestamp().ToInternalValue()))
166 return false;
168 // Please update AW_STATE_VERSION if serialization format is changed.
170 return true;
173 bool RestoreNavigationEntryFromPickle(PickleIterator* iterator,
174 content::NavigationEntry* entry) {
176 string url;
177 if (!iterator->ReadString(&url))
178 return false;
179 entry->SetURL(GURL(url));
183 string virtual_url;
184 if (!iterator->ReadString(&virtual_url))
185 return false;
186 entry->SetVirtualURL(GURL(virtual_url));
190 content::Referrer referrer;
191 string referrer_url;
192 int policy;
194 if (!iterator->ReadString(&referrer_url))
195 return false;
196 if (!iterator->ReadInt(&policy))
197 return false;
199 referrer.url = GURL(referrer_url);
200 referrer.policy = static_cast<WebKit::WebReferrerPolicy>(policy);
201 entry->SetReferrer(referrer);
205 string16 title;
206 if (!iterator->ReadString16(&title))
207 return false;
208 entry->SetTitle(title);
212 string content_state;
213 if (!iterator->ReadString(&content_state))
214 return false;
215 entry->SetPageState(
216 content::PageState::CreateFromEncodedData(content_state));
220 bool has_post_data;
221 if (!iterator->ReadBool(&has_post_data))
222 return false;
223 entry->SetHasPostData(has_post_data);
227 string original_request_url;
228 if (!iterator->ReadString(&original_request_url))
229 return false;
230 entry->SetOriginalRequestURL(GURL(original_request_url));
234 string base_url_for_data_url;
235 if (!iterator->ReadString(&base_url_for_data_url))
236 return false;
237 entry->SetBaseURLForDataURL(GURL(base_url_for_data_url));
241 bool is_overriding_user_agent;
242 if (!iterator->ReadBool(&is_overriding_user_agent))
243 return false;
244 entry->SetIsOverridingUserAgent(is_overriding_user_agent);
248 int64 timestamp;
249 if (!iterator->ReadInt64(&timestamp))
250 return false;
251 entry->SetTimestamp(base::Time::FromInternalValue(timestamp));
254 return true;
257 } // namespace internal
259 } // namespace android_webview