summaryrefslogtreecommitdiffstats
path: root/android_webview
diff options
context:
space:
mode:
authorboliu@chromium.org <boliu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-21 12:34:09 +0000
committerboliu@chromium.org <boliu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-21 12:34:09 +0000
commit1f0d041d875f287e1da906c39db249f713433ef2 (patch)
tree3c193ea4634a524e511967722d9f582571451d3a /android_webview
parentf45a5f17a7cd4b7819f59fd0048cf6f6f37113b0 (diff)
downloadchromium_src-1f0d041d875f287e1da906c39db249f713433ef2.zip
chromium_src-1f0d041d875f287e1da906c39db249f713433ef2.tar.gz
chromium_src-1f0d041d875f287e1da906c39db249f713433ef2.tar.bz2
Android WebView save/restoreState and backForardList Part 1
Design for save/restoreState is do all serialization in native and pass an opaque byte array to java to put into the bundle. This patch contains the native code to (de)serialize a WebContents with some unit test coverage. Reasons for not re-using TabNavigation under chrome/: * Android WebView has different requirements for fields to store since we are the only ones using values like base_url_for_data_url. * TabNavigation does unnecessary copying of data, which in Android WebView case, is undesired since save/restore is called in Android very frequently. * TabNavigation is tightly integrated with the rest of chrome session restore and sync code, and has other purpose in addition to serializing NavigationEntry. Optimization-wise, there will be an unnecessary copy when converting native to java byte array. Only way to avoid it is to know the allocation size before pickling starts. Maybe consider pre-computing the size (brittle), or use chrome's design of capping the size of the data and throwing away old entries and "less important" information. Only consider this if speed becomes a problem. BUG= Android WebView only change. Ran through trybots. NOTRY=true Review URL: https://chromiumcodereview.appspot.com/11420056 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@169024 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'android_webview')
-rw-r--r--android_webview/android_webview_tests.gypi1
-rw-r--r--android_webview/native/state_serializer.cc245
-rw-r--r--android_webview/native/state_serializer.h50
-rw-r--r--android_webview/native/state_serializer_unittests.cc86
-rw-r--r--android_webview/native/webview_native.gyp4
5 files changed, 385 insertions, 1 deletions
diff --git a/android_webview/android_webview_tests.gypi b/android_webview/android_webview_tests.gypi
index 20585b5..fb9317f 100644
--- a/android_webview/android_webview_tests.gypi
+++ b/android_webview/android_webview_tests.gypi
@@ -45,6 +45,7 @@
'sources': [
'lib/main/webview_tests.cc',
'native/android_stream_reader_url_request_job_unittests.cc',
+ 'native/state_serializer_unittests.cc',
],
},
{
diff --git a/android_webview/native/state_serializer.cc b/android_webview/native/state_serializer.cc
new file mode 100644
index 0000000..a777cd8e9
--- /dev/null
+++ b/android_webview/native/state_serializer.cc
@@ -0,0 +1,245 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "android_webview/native/state_serializer.h"
+
+#include <string>
+
+#include "base/memory/scoped_vector.h"
+#include "base/pickle.h"
+#include "base/time.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/web_contents.h"
+
+// Reasons for not re-using TabNavigation under chrome/ as of 20121116:
+// * Android WebView has different requirements for fields to store since
+// we are the only ones using values like BaseURLForDataURL.
+// * TabNavigation does unnecessary copying of data, which in Android
+// WebView case, is undesired since save/restore is called in Android
+// very frequently.
+// * TabNavigation is tightly integrated with the rest of chrome session
+// restore and sync code, and has other purpose in addition to serializing
+// NavigationEntry.
+
+using std::string;
+
+namespace android_webview {
+
+namespace {
+
+// Sanity check value that we are restoring from a valid pickle.
+// This can potentially used as an actual serialization version number in the
+// future if we ever decide to support restoring from older versions.
+const uint32 AW_STATE_VERSION = 20121116;
+
+} // namespace
+
+bool WriteToPickle(const content::WebContents& web_contents,
+ Pickle* pickle) {
+ DCHECK(pickle);
+
+ if (!internal::WriteHeaderToPickle(pickle))
+ return false;
+
+ const content::NavigationController& controller =
+ web_contents.GetController();
+ const int entry_count = controller.GetEntryCount();
+ const int selected_entry = controller.GetCurrentEntryIndex();
+ DCHECK(entry_count >= 0);
+ DCHECK(selected_entry >= -1); // -1 is valid
+ DCHECK(selected_entry < entry_count);
+
+ if (!pickle->WriteInt(entry_count))
+ return false;
+
+ if (!pickle->WriteInt(selected_entry))
+ return false;
+
+ for (int i = 0; i < entry_count; ++i) {
+ if (!internal::WriteNavigationEntryToPickle(*controller.GetEntryAtIndex(i),
+ pickle))
+ return false;
+ }
+
+ // Please update AW_STATE_VERSION if serialization format is changed.
+
+ return true;
+}
+
+bool RestoreFromPickle(PickleIterator* iterator,
+ content::WebContents* web_contents) {
+ DCHECK(iterator);
+ DCHECK(web_contents);
+
+ if (!internal::RestoreHeaderFromPickle(iterator))
+ return false;
+
+ int entry_count = -1;
+ int selected_entry = -2; // -1 is a valid value
+
+ if (!iterator->ReadInt(&entry_count))
+ return false;
+
+ if (!iterator->ReadInt(&selected_entry))
+ return false;
+
+ if (entry_count < 0)
+ return false;
+ if (selected_entry < -1)
+ return false;
+ if (selected_entry >= entry_count)
+ return false;
+
+ ScopedVector<content::NavigationEntry> restored_entries;
+ for (int i = 0; i < entry_count; ++i) {
+ restored_entries.push_back(content::NavigationEntry::Create());
+ if (!internal::RestoreNavigationEntryFromPickle(iterator,
+ restored_entries[i]))
+ return false;
+ }
+
+ // |web_contents| takes ownership of these entries after this call.
+ web_contents->GetController().Restore(
+ selected_entry,
+ content::NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
+ &restored_entries.get());
+ DCHECK_EQ(0u, restored_entries.size());
+
+ return true;
+}
+
+namespace internal {
+
+bool WriteHeaderToPickle(Pickle* pickle) {
+ return pickle->WriteUInt32(AW_STATE_VERSION);
+}
+
+bool RestoreHeaderFromPickle(PickleIterator* iterator) {
+ uint32 state_version = -1;
+ if (!iterator->ReadUInt32(&state_version))
+ return false;
+
+ if (AW_STATE_VERSION != state_version)
+ return false;
+
+ return true;
+}
+
+bool WriteNavigationEntryToPickle(const content::NavigationEntry& entry,
+ Pickle* pickle) {
+ if (!pickle->WriteString(entry.GetURL().spec()))
+ return false;
+
+ if (!pickle->WriteString(entry.GetVirtualURL().spec()))
+ return false;
+
+ const content::Referrer& referrer = entry.GetReferrer();
+ if (!pickle->WriteString(referrer.url.spec()))
+ return false;
+ if (!pickle->WriteInt(static_cast<int>(referrer.policy)))
+ return false;
+
+ if (!pickle->WriteString16(entry.GetTitle()))
+ return false;
+
+ if (!pickle->WriteString(entry.GetContentState()))
+ return false;
+
+ if (!pickle->WriteBool(static_cast<int>(entry.GetHasPostData())))
+ return false;
+
+ if (!pickle->WriteString(entry.GetOriginalRequestURL().spec()))
+ return false;
+
+ if (!pickle->WriteBool(static_cast<int>(entry.GetIsOverridingUserAgent())))
+ return false;
+
+ if (!pickle->WriteInt64(entry.GetTimestamp().ToInternalValue()))
+ return false;
+
+ // Please update AW_STATE_VERSION if serialization format is changed.
+
+ return true;
+}
+
+bool RestoreNavigationEntryFromPickle(PickleIterator* iterator,
+ content::NavigationEntry* entry) {
+ {
+ string url;
+ if (!iterator->ReadString(&url))
+ return false;
+ entry->SetURL(GURL(url));
+ }
+
+ {
+ string virtual_url;
+ if (!iterator->ReadString(&virtual_url))
+ return false;
+ entry->SetVirtualURL(GURL(virtual_url));
+ }
+
+ {
+ content::Referrer referrer;
+ string referrer_url;
+ int policy;
+
+ if (!iterator->ReadString(&referrer_url))
+ return false;
+ if (!iterator->ReadInt(&policy))
+ return false;
+
+ referrer.url = GURL(referrer_url);
+ referrer.policy = static_cast<WebKit::WebReferrerPolicy>(policy);
+ entry->SetReferrer(referrer);
+ }
+
+ {
+ string16 title;
+ if (!iterator->ReadString16(&title))
+ return false;
+ entry->SetTitle(title);
+ }
+
+ {
+ string content_state;
+ if (!iterator->ReadString(&content_state))
+ return false;
+ entry->SetContentState(content_state);
+ }
+
+ {
+ bool has_post_data;
+ if (!iterator->ReadBool(&has_post_data))
+ return false;
+ entry->SetHasPostData(has_post_data);
+ }
+
+ {
+ string original_request_url;
+ if (!iterator->ReadString(&original_request_url))
+ return false;
+ entry->SetOriginalRequestURL(GURL(original_request_url));
+ }
+
+ {
+ bool is_overriding_user_agent;
+ if (!iterator->ReadBool(&is_overriding_user_agent))
+ return false;
+ entry->SetIsOverridingUserAgent(is_overriding_user_agent);
+ }
+
+ {
+ int64 timestamp;
+ if (!iterator->ReadInt64(&timestamp))
+ return false;
+ entry->SetTimestamp(base::Time::FromInternalValue(timestamp));
+ }
+
+ return true;
+}
+
+} // namespace internal
+
+} // namespace android_webview
diff --git a/android_webview/native/state_serializer.h b/android_webview/native/state_serializer.h
new file mode 100644
index 0000000..3dc6181
--- /dev/null
+++ b/android_webview/native/state_serializer.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef ANDROID_WEBVIEW_NATIVE_STATE_SERIALIZER_H_
+#define ANDROID_WEBVIEW_NATIVE_STATE_SERIALIZER_H_
+
+#include "base/compiler_specific.h"
+
+class Pickle;
+class PickleIterator;
+
+namespace content {
+
+class NavigationEntry;
+class WebContents;
+
+} // namespace content
+
+namespace android_webview {
+
+// Write and restore a WebContents to and from a pickle. Return true on
+// success.
+
+// Note that |pickle| may be changed even if function returns false.
+bool WriteToPickle(const content::WebContents& web_contents,
+ Pickle* pickle) WARN_UNUSED_RESULT;
+
+// |web_contents| will not be modified if function returns false.
+bool RestoreFromPickle(PickleIterator* iterator,
+ content::WebContents* web_contents) WARN_UNUSED_RESULT;
+
+
+namespace internal {
+// Functions below are individual helper functiosn called by functions above.
+// They are broken up for unit testing, and should not be called out side of
+// tests.
+bool WriteHeaderToPickle(Pickle* pickle) WARN_UNUSED_RESULT;
+bool RestoreHeaderFromPickle(PickleIterator* iterator) WARN_UNUSED_RESULT;
+bool WriteNavigationEntryToPickle(const content::NavigationEntry& entry,
+ Pickle* pickle) WARN_UNUSED_RESULT;
+bool RestoreNavigationEntryFromPickle(
+ PickleIterator* iterator,
+ content::NavigationEntry* entry) WARN_UNUSED_RESULT;
+
+} // namespace interanl
+
+} // namespace android_webview
+
+#endif // ANDROID_WEBVIEW_NATIVE_STATE_SERIALIZER_H_
diff --git a/android_webview/native/state_serializer_unittests.cc b/android_webview/native/state_serializer_unittests.cc
new file mode 100644
index 0000000..44349fe
--- /dev/null
+++ b/android_webview/native/state_serializer_unittests.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "android_webview/native/state_serializer.h"
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/common/content_client.h"
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace android_webview {
+
+TEST(AndroidWebViewStateSerializerTest, TestHeaderSerialization) {
+ Pickle pickle;
+ bool result = internal::WriteHeaderToPickle(&pickle);
+ EXPECT_TRUE(result);
+
+ PickleIterator iterator(pickle);
+ result = internal::RestoreHeaderFromPickle(&iterator);
+ EXPECT_TRUE(result);
+}
+
+TEST(AndroidWebViewStateSerializerTest, TestNavigationEntrySerialization) {
+ // This is required for NavigationEntry::Create.
+ content::ContentClient content_client;
+ content::ContentBrowserClient browser_client;
+ content_client.set_browser_for_testing(&browser_client);
+ content::SetContentClient(&content_client);
+
+ scoped_ptr<content::NavigationEntry> entry(
+ content::NavigationEntry::Create());
+
+ const GURL url("http://url");
+ const GURL virtual_url("http://virtual_url");
+ content::Referrer referrer;
+ referrer.url = GURL("http://referrer_url");
+ referrer.policy = WebKit::WebReferrerPolicyOrigin;
+ const string16 title(UTF8ToUTF16("title"));
+ const string content_state("completely bogus state");
+ const bool has_post_data = true;
+ const GURL original_request_url("http://original_request_url");
+ const bool is_overriding_user_agent = true;
+ const base::Time timestamp = base::Time::FromInternalValue(12345);
+
+ entry->SetURL(url);
+ entry->SetVirtualURL(virtual_url);
+ entry->SetReferrer(referrer);
+ entry->SetTitle(title);
+ entry->SetContentState(content_state);
+ entry->SetHasPostData(has_post_data);
+ entry->SetOriginalRequestURL(original_request_url);
+ entry->SetIsOverridingUserAgent(is_overriding_user_agent);
+ entry->SetTimestamp(timestamp);
+
+ Pickle pickle;
+ bool result = internal::WriteNavigationEntryToPickle(*entry, &pickle);
+ EXPECT_TRUE(result);
+
+ scoped_ptr<content::NavigationEntry> copy(content::NavigationEntry::Create());
+ PickleIterator iterator(pickle);
+ result = internal::RestoreNavigationEntryFromPickle(&iterator, copy.get());
+ EXPECT_TRUE(result);
+
+ EXPECT_EQ(url, copy->GetURL());
+ EXPECT_EQ(virtual_url, copy->GetVirtualURL());
+ EXPECT_EQ(referrer.url, copy->GetReferrer().url);
+ EXPECT_EQ(referrer.policy, copy->GetReferrer().policy);
+ EXPECT_EQ(title, copy->GetTitle());
+ EXPECT_EQ(content_state, copy->GetContentState());
+ EXPECT_EQ(has_post_data, copy->GetHasPostData());
+ EXPECT_EQ(original_request_url, copy->GetOriginalRequestURL());
+ EXPECT_EQ(is_overriding_user_agent, copy->GetIsOverridingUserAgent());
+ EXPECT_EQ(timestamp, copy->GetTimestamp());
+}
+
+} // namespace android_webview
diff --git a/android_webview/native/webview_native.gyp b/android_webview/native/webview_native.gyp
index 3bdc34b..fb3b09a 100644
--- a/android_webview/native/webview_native.gyp
+++ b/android_webview/native/webview_native.gyp
@@ -36,8 +36,8 @@
'aw_http_auth_handler.h',
'aw_javascript_dialog_creator.cc',
'aw_javascript_dialog_creator.h',
- 'aw_resource.h',
'aw_resource.cc',
+ 'aw_resource.h',
'aw_web_contents_delegate.cc',
'aw_web_contents_delegate.h',
'cookie_manager.cc',
@@ -47,6 +47,8 @@
'js_result_handler.cc',
'js_result_handler.h',
'net_init_native_callback.cc',
+ 'state_serializer.cc',
+ 'state_serializer.h',
],
},
{