************************* G4 reminder *************************
These new files:
c:\MyDocs\Gears1\googleclient\gears\opensource\gears\installer\iemobile\periodic_checker.cc
are missing unit tests.
***************************************************************
Hello andreip,
I'd like you to do a code review. Please execute
g4 diff -c 8606512
or point your web browser to
http://mondrian/8606512
to review the following code:
Change 8606512 by [EMAIL PROTECTED] on 2008/10/15 18:11:39 *pending*
Factors out browser-independent parts of CabUpdater for WinCE.
R=andreip
[EMAIL PROTECTED]
DELTA=1046 (593 added, 434 deleted, 19 changed)
OCL=8606512
Affected files ...
... //depot/googleclient/gears/opensource/gears/Makefile#192 edit
...
//depot/googleclient/gears/opensource/gears/installer/iemobile/cab_updater.cc#4
edit
...
//depot/googleclient/gears/opensource/gears/installer/iemobile/cab_updater.h#2
edit
...
//depot/googleclient/gears/opensource/gears/installer/iemobile/periodic_checker.cc#1
add
...
//depot/googleclient/gears/opensource/gears/installer/iemobile/periodic_checker.h#1
add
1046 delta lines: 593 added, 434 deleted, 19 changed
Also consider running:
g4 lint -c 8606512
which verifies that the changelist doesn't introduce new style violations.
If you can't do the review, please let me know as soon as possible. During
your review, please ensure that all new code has corresponding unit tests and
that existing unit tests are updated appropriately. Visit
http://www/eng/code_review.html for more information.
This is a semiautomated message from "g4 mail". Complaints or suggestions?
Mail [EMAIL PROTECTED]
Change 8606512 by [EMAIL PROTECTED] on 2008/10/15 18:11:39 *pending*
Factors out browser-independent parts of CabUpdater for WinCE.
Affected files ...
... //depot/googleclient/gears/opensource/gears/Makefile#192 edit
...
//depot/googleclient/gears/opensource/gears/installer/iemobile/cab_updater.cc#4
edit
...
//depot/googleclient/gears/opensource/gears/installer/iemobile/cab_updater.h#2
edit
...
//depot/googleclient/gears/opensource/gears/installer/iemobile/periodic_checker.cc#1
add
...
//depot/googleclient/gears/opensource/gears/installer/iemobile/periodic_checker.h#1
add
==== //depot/googleclient/gears/opensource/gears/Makefile#192 -
c:\MyDocs\Gears1/googleclient/gears/opensource/gears/Makefile ====
# action=edit type=text
--- googleclient/gears/opensource/gears/Makefile 2008-10-17
16:32:52.000000000 +0100
+++ googleclient/gears/opensource/gears/Makefile 2008-10-17
14:37:14.000000000 +0100
@@ -2354,6 +2354,7 @@
# TODO(cprince): move this to another source path; IE_MODULE_DLL links it.
IE_CPPSRCS += \
cab_updater.cc \
+ periodic_checker.cc \
$(NULL)
endif # IE
endif # wince
@@ -2409,7 +2410,8 @@
geolocation_db.cc \
geolocation_db_test.cc \
geolocation_test.cc \
- gps_location_provider_wince.cc \
+ gps_device_wince.cc \
+ gps_location_provider.cc \
location_provider.cc \
location_provider_pool.cc \
network_location_provider.cc \
====
//depot/googleclient/gears/opensource/gears/installer/iemobile/cab_updater.cc#4
-
c:\MyDocs\Gears1/googleclient/gears/opensource/gears/installer/iemobile/cab_updater.cc
====
# action=edit type=text
--- googleclient/gears/opensource/gears/installer/iemobile/cab_updater.cc
2008-10-17 00:04:10.000000000 +0100
+++ googleclient/gears/opensource/gears/installer/iemobile/cab_updater.cc
2008-10-17 16:28:18.000000000 +0100
@@ -23,52 +23,23 @@
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#include <string>
-
#include "gears/installer/iemobile/cab_updater.h"
-#include "gears/base/common/common_ie.h"
+#include "gears/base/common/string16.h"
#include "gears/base/common/thread_locals.h"
-#include "gears/base/common/wince_compatibility.h"
-#include "gears/base/ie/activex_utils.h"
#include "gears/base/ie/bho.h"
-#include "gears/blob/blob_interface.h"
-#include "gears/blob/blob_utils.h"
#include "gears/installer/iemobile/resource.h"
-const char16* kUpgradeUrl = reinterpret_cast<const char16*>( // STRING16()
- // TODO(andreip): When updating the Gears 'guid' field, consider switching
- // 'application' to a GUID that means Pocket IE (to match Firefox pings).
- // Also remind cprince to update the stats logic when 'guid' changes.
- L"http://tools.google.com/service/update2/ff?"
- L"guid=%7Bc3fc95dBb-cd75-4f3d-a586-bcb7D004784c%7D"
- L"&version=" PRODUCT_VERSION_STRING
- L"&application=%7Bc3fc95dBb-cd75-4f3d-a586-bcb7D004784c%7D"
- L"&appversion=1.0"
-#ifdef OFFICIAL_BUILD
- L"&os=wince&dist=google");
-#else
- L"&os=wince&dist=google&dev=1");
-#endif
+// TODO(andreip): When updating the Gears 'guid' field, consider switching
+// 'application' to a GUID that means Pocket IE (to match Firefox pings).
+// Also remind cprince to update the stats logic when 'guid' changes.
+const char16* kApplicationId = L"%7Bc3fc95dBb-cd75-4f3d-a586-bcb7D004784c%7D";
+
// The topic for the message system.
const char16* kTopic = STRING16(L"Cab Update Event");
// The key for ThreadLocals.
const ThreadLocals::Slot kThreadLocalKey = ThreadLocals::Alloc();
-// String constants for XML parsing
-// Query language
-const char16* kQueryLanguage = STRING16(L"XPath");
-const char16* kQueryLanguageProperty = STRING16(L"SelectionLanguage");
-// The document namespaces (space delimited)
-const char16* kNamespace =
- STRING16(L"xmlns:RDF='http://www.w3.org/1999/02/22-rdf-syntax-ns#' "
- L"xmlns:em='http://www.mozilla.org/2004/em-rdf#'");
-const char16* kNamespaceProperty = STRING16(L"SelectionNamespaces");
-// The query for version elements: select the first em:version descendant
-// of the root element.
-const char16* kVersionQuery = STRING16(L"//em:version[1]");
-// The query for update link elements: select the first em:updateLink
descendant
-// of the root element.
-const char16* kUpdateLinkQuery = STRING16(L"//em:updateLink[1]");
+
// The delay before the first update.
const int32 kFirstUpdatePeriod = (1000 * 60 * 2); // 2 minutes
// The time interval between the rest of the update checks.
@@ -76,103 +47,6 @@
// A grace period after a connection event. Setting up a new connection
// can take time so we wait a little after the event.
const int32 kGracePeriod = (1000 * 30); // 30 seconds
-
-// A simple task that visits the upgrade url and stops after the first
redirect.
-class VersionFetchTask : public AsyncTask {
- public:
- VersionFetchTask() : AsyncTask(NULL) {}
- bool Init();
-
- enum {
- VERSION_FETCH_TASK_COMPLETE = 0
- };
-
- const char16* Url() const;
- const char16* LatestVersion() const;
-
- private:
- // AsyncTask
- virtual void Run();
- // Internal
-
- // Parses XML and extracts the Gears version number and download URL.
- bool ExtractVersionAndDownloadUrl(const std::string16& xml);
-
- std::string16 url_;
- std::string16 latest_version_;
-
- DISALLOW_EVIL_CONSTRUCTORS(VersionFetchTask);
-};
-
-// A thread that wakes up periodically and does the check.
-class PeriodicChecker : public CWindowImpl<PeriodicChecker> {
- public:
- // Simple factory method.
- static PeriodicChecker* CreateChecker();
- // Initializes the checker and sets the desired times between the updates.
- bool Init(int32 first_period, int32 normal_period, int32 grace_period);
- // Starts the checker thread.
- void Start();
- // Stops the checker thread.
- void Stop();
- ~PeriodicChecker();
-
- private:
- // CWindowImpl
- BEGIN_MSG_MAP(PeriodicChecker)
- MESSAGE_HANDLER(WM_TIMER, OnTimer)
- MESSAGE_HANDLER(WM_FETCH_TASK_COMPLETE, OnComplete)
- END_MSG_MAP()
-
- // Internal
- PeriodicChecker();
- // TODO(andreip): aggregate all Gears WM_USER messages in the same
- // header to avoid overlap.
- static const int kUpdateTaskMessageBase = WM_USER;
- static const int
- WM_FETCH_TASK_COMPLETE =
- VersionFetchTask::VERSION_FETCH_TASK_COMPLETE + kUpdateTaskMessageBase;
- // Message handlers.
- LRESULT OnTimer(UINT message, WPARAM w, LPARAM l, BOOL& handled);
- LRESULT OnComplete(UINT message, WPARAM success, LPARAM task, BOOL& handled);
- // This message handler is different because it needs to be registered at
- // runtime with RegisterWindowMessage (it's comming from the connection
- // manager process and that API only exposes a string).
- void OnConnectionStatusChanged();
- // Thread entry.
- static unsigned int _stdcall ThreadMain(void* checker);
- // Runs the Windows message loop machinery (essentially a lot of
boilerplate).
- void RunMessageLoop();
- // Timer utilitiy.
- void ResetTimer(int32 period);
- // The delay before the first check.
- int32 first_period_;
- // The normal time interval between checks.
- int32 normal_period_;
- // The time interval to wait after a connection up event.
- int32 grace_period_;
- // When this is signaled, the thread exists.
- CEvent stop_event_;
- // The thread handle.
- HANDLE thread_;
- // The window handle.
- HWND window_;
- // The timer ID.
- int timer_;
- // The task responsible for doing the HTTP requests to upgrade URL.
- VersionFetchTask task_;
- // Is the task running?
- bool is_running_;
- // Was this a normal timer evenr?
- bool normal_timer_event_;
- // The message ID used for listening to connection status events.
- uint32 con_mgr_msg_;
-
- DISALLOW_EVIL_CONSTRUCTORS(PeriodicChecker);
-};
-
-//
-----------------------------------------------------------------------------
-// CabUpdater
CabUpdater::CabUpdater()
: checker_(PeriodicChecker::CreateChecker()),
@@ -187,7 +61,8 @@
void CabUpdater::SetSiteAndStart(IWebBrowser2* browser) {
ASSERT(checker_);
browser_ = browser;
- if (checker_->Init(kFirstUpdatePeriod, kUpdatePeriod, kGracePeriod)) {
+ if (checker_->Init(kFirstUpdatePeriod, kUpdatePeriod, kGracePeriod,
+ kApplicationId, this)) {
MessageService::GetInstance()->AddObserver(this, kTopic);
// We get stopped when the DLL unloads.
ThreadLocals::SetValue(kThreadLocalKey, this, &Stop);
@@ -232,7 +107,15 @@
void CabUpdater::Stop(void* self) {
ASSERT(self);
CabUpdater* updater = reinterpret_cast<CabUpdater*>(self);
- updater->checker_->Stop();
+ // Stop the periodic checker, without waiting for it to clean up. In general
+ // this is dangerous, because the periodic checker's worker thread may
attempt
+ // to access the object's internals, or call back to this object, after these
+ // objects have been deleted. Hovever, in this case, the browser process is
+ // being shut down and the checker's thread is likely to be forcefully
+ // terminated before it completes, causing this call to block indefinitely if
+ // we wait for clean up. Furthermore, any crashes that occur from this point
+ // on will not be noticed as the browser shuts down!
+ updater->checker_->Stop(false);
MessageService::GetInstance()->RemoveObserver(updater, kTopic);
}
@@ -259,294 +142,8 @@
MB_YESNO | MB_ICONQUESTION));
}
-//
-----------------------------------------------------------------------------
-// VersionFetchTask
-
-bool VersionFetchTask::Init() {
- if (is_initialized_) return true;
- return AsyncTask::Init();
+void CabUpdater::UpdateUrlAvailable(const std::string16 &url) {
+ // Marshall the callback to the browser thread so that we can show the
dialog.
+ SerializableString16* update_event = new SerializableString16(url.c_str());
+ MessageService::GetInstance()->NotifyObservers(kTopic, update_event);
}
-
-const char16* VersionFetchTask::LatestVersion() const {
- return latest_version_.c_str();
-}
-
-const char16* VersionFetchTask::Url() const {
- return url_.c_str();
-}
-
-// AsyncTask
-void VersionFetchTask::Run() {
- WebCacheDB::PayloadInfo payload;
- scoped_refptr<BlobInterface> payload_data;
- bool was_redirected;
- std::string16 error_msg;
- std::string16 url;
- bool success = false;
- if (ActiveXUtils::IsOnline() &&
- AsyncTask::HttpGet(kUpgradeUrl,
- true,
- NULL,
- NULL,
- NULL,
- &payload,
- &payload_data,
- &was_redirected,
- &url,
- &error_msg)) {
- std::string16 xml;
- const std::string16 charset;
- // payload.data can be empty in case of a 30x response.
- // The update server does not redirect, so we treat this as an error.
- if (payload_data->Length() &&
- BlobToString16(payload_data.get(), charset, &xml) &&
- ExtractVersionAndDownloadUrl(xml)) {
- success = true;
- }
- }
- NotifyListener(VERSION_FETCH_TASK_COMPLETE, success);
-}
-
-// Internal
-bool VersionFetchTask::ExtractVersionAndDownloadUrl(const std::string16& xml) {
- CComPtr<IXMLDOMDocument2> document;
- // Note that CoInitializeEx is called by the parent class.
- if (FAILED(document.CoCreateInstance(
- CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER))) {
- return false;
- }
- ASSERT(document);
- document->put_async(VARIANT_FALSE);
- VARIANT_BOOL success;
- // Load the document
- if (FAILED(document->loadXML(const_cast<BSTR>(xml.c_str()), &success)) ||
- success == VARIANT_FALSE) {
- return false;
- }
- // Set the query language and namespace
- VARIANT var = {0};
- CComBSTR bstr(kNamespace);
- bstr.CopyTo(&var);
- HRESULT hr = document->setProperty(const_cast<BSTR>(kNamespaceProperty),
var);
- VariantClear(&var);
- if (FAILED(hr)) return false;
-
- bstr = kQueryLanguage; // this frees the old string stored by bstr.
- bstr.CopyTo(&var);
- hr = document->setProperty(const_cast<BSTR>(kQueryLanguageProperty), var);
- VariantClear(&var);
- if (FAILED(hr)) return false;
-
- // Run the version query
- IXMLDOMNodeList* node_list = NULL;
- long number_of_nodes = 0; // get_length() needs a ptr to long
- if (FAILED(document->selectNodes(const_cast<BSTR>(kVersionQuery),
- &node_list)) ||
- FAILED(node_list->get_length(&number_of_nodes))) {
- return false;
- }
- // We expect 0 or 1 element, depending on whether an update is available.
- // We return early if we get 0 elements (no updates available).
- if (number_of_nodes == 0) return false;
- ASSERT(number_of_nodes == 1);
- IXMLDOMNode* node;
- if (FAILED(node_list->get_item(0, &node))) {
- return false;
- }
- BSTR version_text;
- if (FAILED(node->get_text(&version_text))) {
- return false;
- }
- latest_version_ = version_text;
- // Hurray, done with the version. Now the update link.
- number_of_nodes = 0;
- if (FAILED(document->selectNodes(const_cast<BSTR>(kUpdateLinkQuery),
- &node_list)) ||
- FAILED(node_list->get_length(&number_of_nodes))) {
- return false;
- }
- // We expect 0 or 1 element, depending on whether an update is available.
- // We return early if we get 0 elements (no updates available).
- if (number_of_nodes == 0) return false;
- ASSERT(number_of_nodes == 1);
- if (FAILED(node_list->get_item(0, &node))) {
- return false;
- }
- BSTR update_link;
- if (FAILED(node->get_text(&update_link))) {
- return false;
- }
- url_ = update_link;
- return true;
-}
-
-//
-----------------------------------------------------------------------------
-// PeriodicChecker
-
-// static
-PeriodicChecker* PeriodicChecker::CreateChecker() {
- return new PeriodicChecker();
-}
-
-bool PeriodicChecker::Init(int32 first_period, int32 normal_period,
- int32 grace_period) {
- first_period_ = first_period;
- normal_period_ = normal_period;
- grace_period_ = grace_period;
- return (TRUE == stop_event_.Create(NULL, FALSE, FALSE, NULL));
-}
-
-PeriodicChecker::PeriodicChecker()
- : first_period_(0),
- normal_period_(0),
- grace_period_(0),
- thread_(NULL),
- timer_(1),
- window_(NULL),
- is_running_(false),
- normal_timer_event_(false) {
-}
-
-PeriodicChecker::~PeriodicChecker() {
- ASSERT(!thread_);
-}
-
-void PeriodicChecker::Start() {
- ASSERT(!thread_);
- // Start the thread.
- thread_ = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, &ThreadMain,
- this, 0, NULL));
- ASSERT(thread_ != NULL);
-}
-
-void PeriodicChecker::Stop() {
- // This is called only from the main thread, when the DLL unloads.
- ASSERT(thread_);
- stop_event_.Set();
-}
-
-unsigned int __stdcall PeriodicChecker::ThreadMain(void* checker) {
- PeriodicChecker* self = reinterpret_cast<PeriodicChecker*>(checker);
- self->RunMessageLoop();
- return 0;
-}
-
-void PeriodicChecker::RunMessageLoop() {
- // Create the thread window.
- window_ = Create(kMessageOnlyWindowParent, // parent
- NULL, // position
- NULL, // name
- kMessageOnlyWindowStyle); // style
- // Set the timer for the first wait.
- SetTimer(static_cast<unsigned>(timer_),
- static_cast<unsigned>(first_period_),
- NULL);
- con_mgr_msg_ = RegisterWindowMessage(CONNMGR_STATUS_CHANGE_NOTIFICATION_MSG);
- // Run the loop.
- bool done = false;
- HANDLE handles[] = { stop_event_.m_h };
- // Run the message loop.
- while (!done) {
- DWORD rv = MsgWaitForMultipleObjectsEx(ARRAYSIZE(handles),
- handles,
- INFINITE,
- QS_POSTMESSAGE | WM_TIMER,
- 0);
- if (rv == WAIT_OBJECT_0) {
- // stop_event was signalled.
- done = true;
- } else if (rv == WAIT_OBJECT_0 + ARRAYSIZE(handles)) {
- // We have a posted message or a WM_TIMER in the queue. Dispatch them
- // and go back to sleep.
- MSG msg;
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
- TranslateMessage(&msg);
- // We handle this here since, at compile time, we don't know
- // the value of con_mgr_msg_.
- if (msg.message == con_mgr_msg_) OnConnectionStatusChanged();
- DispatchMessage(&msg);
- }
- } else {
- // Something else happened.
- done = true;
- }
- }
- // Kill the timer.
- KillTimer(timer_);
- // Stop any running tasks.
- task_.Abort();
- // Destroy the thread window.
- DestroyWindow();
- // Close and null the thread handle.
- CloseHandle(thread_);
- thread_ = NULL;
-}
-
-LRESULT PeriodicChecker::OnTimer(UINT message,
- WPARAM w,
- LPARAM l,
- BOOL& handled) {
- if (!normal_timer_event_) {
- normal_timer_event_ = true;
- ResetTimer(normal_period_);
- }
- // Depending on how the periodic checker is configured, this can fire
- // while a task is running. We ignore such events.
- if (!is_running_) {
- if (task_.Init()) {
- is_running_ = true;
- task_.SetListenerWindow(window_, kUpdateTaskMessageBase);
- task_.Start();
- }
- }
- handled = TRUE;
- return TRUE;
-}
-
-LRESULT PeriodicChecker::OnComplete(UINT message,
- WPARAM success,
- LPARAM task,
- BOOL& handled) {
- is_running_ = false;
- if (success) {
- // We check for differences between the version strings. If there is a
- // difference, the server version wins.
- if (wcslen(task_.LatestVersion()) &&
- wcslen(task_.Url()) &&
- wcscmp(task_.LatestVersion(), PRODUCT_VERSION_STRING) != 0) {
- SerializableString16* update_event =
- new SerializableString16(task_.Url());
- MessageService::GetInstance()->NotifyObservers(kTopic,
- update_event);
- }
- } else {
- // Failed attempt.
- // If it appears that we don't have a connection,
- // wait for one to appear. Otherwise, the error must have
- // been on the network, so we'll try again tomorrow.
- if (!ActiveXUtils::IsOnline()) {
- ConnMgrRegisterForStatusChangeNotification(TRUE, window_);
- }
- }
- task_.SetListenerWindow(NULL, 0);
- handled = TRUE;
- return TRUE;
-}
-
-void PeriodicChecker::OnConnectionStatusChanged() {
- // Unregister from connection events. We'll register again
- // if the update check fails.
- if (ActiveXUtils::IsOnline()) {
- ConnMgrRegisterForStatusChangeNotification(FALSE, window_);
- // Schedule a check after the grace period.
- normal_timer_event_ = false;
- ResetTimer(grace_period_);
- }
-}
-
-void PeriodicChecker::ResetTimer(int32 period) {
- KillTimer(timer_);
- SetTimer(static_cast<unsigned>(timer_),
- static_cast<unsigned>(period),
- NULL);
-}
====
//depot/googleclient/gears/opensource/gears/installer/iemobile/cab_updater.h#2
-
c:\MyDocs\Gears1/googleclient/gears/opensource/gears/installer/iemobile/cab_updater.h
====
# action=edit type=text
--- googleclient/gears/opensource/gears/installer/iemobile/cab_updater.h
2008-10-17 00:04:10.000000000 +0100
+++ googleclient/gears/opensource/gears/installer/iemobile/cab_updater.h
2008-10-17 16:27:07.000000000 +0100
@@ -22,45 +22,37 @@
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file defines the CabUpdater class, which uses the PeriodicChecker to
+// handle automitic updating.
+//
+// 1. When the Gears BHO is loaded, the CabUpdater is started immediately after
+// the HTTP handler is registered. The PeriodicChecker is configured to check
+// for an update after two minutes and every 24 hours thereafter. The
+// PeriodicChecker is started.
+// 2. If the PeriodicChecker reports a new version, we present the user with a
+// dialog, asking if they would like to upgrade.
+// 3. If the user agrees, the CabUpdater uses the IWebBrowser2 pointer to make
+// the browser download the new CAB.
+// 4. The CabUpdater waits for a new update from the PeriodicChecker and
+// continues from step 2.
#ifndef GEARS_INSTALLER_IEMOBILE_CAB_UPDATER_H__
#define GEARS_INSTALLER_IEMOBILE_CAB_UPDATER_H__
-#include <windows.h>
#include <piedocvw.h>
#include "gears/base/common/common.h"
#include "gears/base/common/message_service.h"
-#include "gears/base/common/sqlite_wrapper.h"
-#include "gears/base/ie/atl_headers.h"
-#include "gears/localserver/common/async_task.h"
-#include "third_party/scoped_ptr/scoped_ptr.h"
+#include "gears/installer/iemobile/periodic_checker.h"
-// This class takes care of periodic version updates. It does this as follows:
-// 1. When the Gears BHO is loaded, CAB updater is started immediately after
-// the HTTP handler is registered.
-// 2. The CAB updater sets up a timer and goes to sleep for some time
-// 3. When the CAB updater wakes up, it does a HTTP GET to the upgrade URL
-// and aborts after the first redirect.
-// 4. When the request completes, the updater inspects the Location header
-// and extracts the latest version number.
-// 5. The CAB updater checks the latest version number vs. the current version
-// number. If the two are different,
-// 6. The CAB updater asks the user if it should proceed with the upgrade. If
-// the user agrees,
-// 7. The CAB updater uses the IWebBrowser2 pointer to make the browser
-// download the new CAB.
-// 8. The updater waits for 24 hours, then continues at step 3.
-
-// Forward declarations
-class PeriodicChecker;
-
-class CabUpdater : public MessageObserverInterface {
+class CabUpdater
+ : public MessageObserverInterface,
+ public PeriodicChecker::ListenerInterface {
public:
CabUpdater();
virtual ~CabUpdater();
- // Starts the updater. Sleep a few seconds and work out if an update check
- // is due.
+ // Starts the updater.
void SetSiteAndStart(IWebBrowser2* browser);
// MessageObserverInterface
@@ -77,6 +69,9 @@
static void Stop(void* self);
// Shows the update dialog to the user.
bool ShowUpdateDialog(HWND browser_window);
+ // PeriodicChecker::ListenerInterface implementation
+ virtual void UpdateUrlAvailable(const std::string16 &url);
+
// We drive the browser through this IWebBrowser2 pointer. Not owned.
IWebBrowser2* browser_;
// The periodic update checker. Owned.
====
//depot/googleclient/gears/opensource/gears/installer/iemobile/periodic_checker.cc#1
-
c:\MyDocs\Gears1/googleclient/gears/opensource/gears/installer/iemobile/periodic_checker.cc
====
# action=add type=text
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ googleclient/gears/opensource/gears/installer/iemobile/periodic_checker.cc
2008-10-17 16:05:41.000000000 +0100
@@ -0,0 +1,433 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
notice,
+// this list of conditions and the following disclaimer in the
documentation
+// and/or other materials provided with the distribution.
+// 3. Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "gears/installer/iemobile/periodic_checker.h"
+
+#include "gears/base/ie/activex_utils.h"
+#include "gears/blob/blob_interface.h"
+#include "gears/blob/blob_utils.h"
+#include "gears/installer/iemobile/resource.h"
+#include "gears/localserver/common/async_task.h"
+#include "genfiles/product_constants.h"
+
+const char16* kUpgradeUrl = L"http://tools.google.com/service/update2/ff?"
+ L"guid=%7Bc3fc95dBb-cd75-4f3d-a586-bcb7D004784c%7D"
+ L"&version=" PRODUCT_VERSION_STRING
+ L"&appversion=1.0"
+ L"&os=wince"
+ L"&dist=google"
+#ifdef OFFICIAL_BUILD
+ // Only pass 'dev=1' for non-official builds.
+#else
+ L"&dev=1"
+#endif
+ L"&application=";
+
+// String constants for XML parsing
+// Query language
+const char16* kQueryLanguage = STRING16(L"XPath");
+const char16* kQueryLanguageProperty = STRING16(L"SelectionLanguage");
+// The document namespaces (space delimited)
+const char16* kNamespace =
+ STRING16(L"xmlns:RDF='http://www.w3.org/1999/02/22-rdf-syntax-ns#' "
+ L"xmlns:em='http://www.mozilla.org/2004/em-rdf#'");
+const char16* kNamespaceProperty = STRING16(L"SelectionNamespaces");
+// The query for version elements: select the first em:version descendant
+// of the root element.
+const char16* kVersionQuery = STRING16(L"//em:version[1]");
+// The query for update link elements: select the first em:updateLink
descendant
+// of the root element.
+const char16* kUpdateLinkQuery = STRING16(L"//em:updateLink[1]");
+
+
+// An implementation of AsyncTaks that makes a request to the upgrade URL and
+// parses the response to extract the latest version number and download URL.
+// Note that redirects are not followed.
+class VersionFetchTask : public AsyncTask {
+ public:
+ // Factory method
+ static VersionFetchTask *Create(const std::string16 &application_id,
+ HWND listener_window,
+ int listener_message_base);
+
+ // Signals the worker thread to stop and asynchronously deletes the object.
+ // No further messages will be sent to the listener once a call to this
method
+ // completes.
+ void StopThreadAndDelete();
+
+ const char16* Url() const;
+ const char16* LatestVersion() const;
+
+ private:
+ // Use Create to create a new instance and StopThreadAndDelete to destroy.
+ VersionFetchTask(const std::string16 &application_id);
+ virtual ~VersionFetchTask() {}
+
+ // AsyncTask implementation
+ virtual void Run();
+
+ // Parses XML and extracts the Gears version number and download URL.
+ bool ExtractVersionAndDownloadUrl(const std::string16& xml);
+
+ std::string16 url_;
+ std::string16 latest_version_;
+
+ std::string16 application_id_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(VersionFetchTask);
+};
+
+
+// static
+PeriodicChecker* PeriodicChecker::CreateChecker() {
+ return new PeriodicChecker();
+}
+
+bool PeriodicChecker::Init(int32 first_period,
+ int32 normal_period,
+ int32 grace_period,
+ const std::string16 &application_id,
+ ListenerInterface *listener) {
+ first_period_ = first_period;
+ normal_period_ = normal_period;
+ grace_period_ = grace_period;
+ application_id_ = application_id;
+ listener_ = listener;
+ return (TRUE == stop_event_.Create(NULL, FALSE, FALSE, NULL)) &&
+ (TRUE == thread_complete_event_.Create(NULL, FALSE, FALSE, NULL));
+}
+
+PeriodicChecker::PeriodicChecker()
+ : first_period_(0),
+ normal_period_(0),
+ grace_period_(0),
+ wait_for_cleanup_(true),
+ thread_(NULL),
+ timer_(1),
+ task_(NULL),
+ window_(NULL),
+ normal_timer_event_(false) {
+}
+
+PeriodicChecker::~PeriodicChecker() {
+#ifdef DEBUG
+ if (wait_for_cleanup_) {
+ ASSERT(!thread_);
+ }
+#endif
+}
+
+void PeriodicChecker::Start() {
+ ASSERT(!thread_);
+ // Start the thread.
+ thread_ = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, &ThreadMain,
+ this, 0, NULL));
+ ASSERT(thread_);
+}
+
+void PeriodicChecker::Stop(bool wait_for_cleanup) {
+ stop_event_.Set();
+ if (wait_for_cleanup) {
+ WaitForSingleObject(thread_complete_event_, INFINITE);
+ } else {
+#ifdef DEBUG
+ wait_for_cleanup_ = false;
+#endif
+ }
+}
+
+unsigned int __stdcall PeriodicChecker::ThreadMain(void* checker) {
+ PeriodicChecker* self = reinterpret_cast<PeriodicChecker*>(checker);
+ self->RunMessageLoop();
+ return 0;
+}
+
+void PeriodicChecker::RunMessageLoop() {
+ // Create the thread window.
+ window_ = Create(kMessageOnlyWindowParent, // parent
+ NULL, // position
+ NULL, // name
+ kMessageOnlyWindowStyle); // style
+ // Set the timer for the first wait.
+ SetTimer(static_cast<unsigned>(timer_),
+ static_cast<unsigned>(first_period_),
+ NULL);
+ con_mgr_msg_ = RegisterWindowMessage(CONNMGR_STATUS_CHANGE_NOTIFICATION_MSG);
+ // Run the loop.
+ bool done = false;
+ HANDLE handles[] = { stop_event_ };
+ // Run the message loop.
+ while (!done) {
+ DWORD rv = MsgWaitForMultipleObjectsEx(ARRAYSIZE(handles),
+ handles,
+ INFINITE,
+ QS_POSTMESSAGE | WM_TIMER,
+ 0);
+ if (rv == WAIT_OBJECT_0) {
+ // stop_event was signalled.
+ done = true;
+ } else if (rv == WAIT_OBJECT_0 + ARRAYSIZE(handles)) {
+ // We have a posted message or a WM_TIMER in the queue. Dispatch them
+ // and go back to sleep.
+ MSG msg;
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&msg);
+ // We handle this here since, at compile time, we don't know
+ // the value of con_mgr_msg_.
+ if (msg.message == con_mgr_msg_) OnConnectionStatusChanged();
+ DispatchMessage(&msg);
+ }
+ } else {
+ // Something else happened.
+ done = true;
+ }
+ }
+ // Kill the timer.
+ KillTimer(timer_);
+ // Stop the task, if it's running.
+ if (task_) {
+ task_->StopThreadAndDelete();
+ task_ = NULL;
+ }
+ // Destroy the thread window.
+ DestroyWindow();
+ // Close and null the thread handle.
+ CloseHandle(thread_);
+ thread_ = NULL;
+
+ thread_complete_event_.Set();
+}
+
+LRESULT PeriodicChecker::OnTimer(UINT message,
+ WPARAM w,
+ LPARAM l,
+ BOOL& handled) {
+ if (!normal_timer_event_) {
+ normal_timer_event_ = true;
+ ResetTimer(normal_period_);
+ }
+ // Depending on how the periodic checker is configured, this can fire
+ // while a task is running. We ignore such events.
+ if (!task_) {
+ task_ = VersionFetchTask::Create(application_id_,
+ window_,
+ kUpdateTaskMessageBase);
+ }
+ handled = TRUE;
+ return TRUE;
+}
+
+LRESULT PeriodicChecker::OnComplete(UINT message,
+ WPARAM success,
+ LPARAM task,
+ BOOL& handled) {
+ assert(task_);
+ if (success) {
+ // We check for differences between the version strings. If there is a
+ // difference, the server version wins.
+ if (wcslen(task_->LatestVersion()) &&
+ wcslen(task_->Url()) &&
+ wcscmp(task_->LatestVersion(), PRODUCT_VERSION_STRING) != 0) {
+ // Call listener
+ listener_->UpdateUrlAvailable(task_->Url());
+ }
+ } else {
+ // Failed attempt.
+ // If it appears that we don't have a connection, wait for one to appear.
+ // Otherwise, the error must have been on the network, so we'll try again
+ // when the timer next expires.
+ if (!ActiveXUtils::IsOnline()) {
+ ConnMgrRegisterForStatusChangeNotification(TRUE, window_);
+ }
+ }
+
+ // Now that we have handled the task message, we can delete it.
+ task_->StopThreadAndDelete();
+ task_ = NULL;
+
+ handled = TRUE;
+ return TRUE;
+}
+
+void PeriodicChecker::OnConnectionStatusChanged() {
+ // Unregister from connection events. We'll register again
+ // if the update check fails.
+ if (ActiveXUtils::IsOnline()) {
+ ConnMgrRegisterForStatusChangeNotification(FALSE, window_);
+ // Schedule a check after the grace period.
+ normal_timer_event_ = false;
+ ResetTimer(grace_period_);
+ }
+}
+
+void PeriodicChecker::ResetTimer(int32 period) {
+ KillTimer(timer_);
+ SetTimer(static_cast<unsigned>(timer_),
+ static_cast<unsigned>(period),
+ NULL);
+}
+
+//
-----------------------------------------------------------------------------
+// VersionFetchTask
+
+// static
+VersionFetchTask *VersionFetchTask::Create(
+ const std::string16 &application_id,
+ HWND listener_window,
+ int listener_message_base) {
+ VersionFetchTask *task = new VersionFetchTask(application_id);
+ task->SetListenerWindow(listener_window, listener_message_base);
+ if (!task) {
+ assert(false);
+ return NULL;
+ }
+ if (!task->Init() || !task->Start()) {
+ delete task;
+ return NULL;
+ }
+ return task;
+}
+
+VersionFetchTask::VersionFetchTask(const std::string16 &application_id)
+ : AsyncTask(NULL),
+ application_id_(application_id) {
+}
+
+void VersionFetchTask::StopThreadAndDelete() {
+ SetListenerWindow(NULL, 0);
+ Abort();
+ DeleteWhenDone();
+}
+
+const char16* VersionFetchTask::LatestVersion() const {
+ return latest_version_.c_str();
+}
+
+const char16* VersionFetchTask::Url() const {
+ return url_.c_str();
+}
+
+// AsyncTask
+void VersionFetchTask::Run() {
+ WebCacheDB::PayloadInfo payload;
+ scoped_refptr<BlobInterface> payload_data;
+ bool success = false;
+ std::string16 url = kUpgradeUrl + application_id_;
+ if (ActiveXUtils::IsOnline() &&
+ AsyncTask::HttpGet(url.c_str(),
+ true,
+ NULL,
+ NULL,
+ NULL,
+ &payload,
+ &payload_data,
+ NULL, // was_redirected
+ NULL, // full_redirect_url
+ NULL)) { // error_msg
+ std::string16 xml;
+ const std::string16 charset;
+ // payload.data can be empty in case of a 30x response.
+ // The update server does not redirect, so we treat this as an error.
+ if (payload_data->Length() &&
+ BlobToString16(payload_data.get(), charset, &xml) &&
+ ExtractVersionAndDownloadUrl(xml)) {
+ success = true;
+ }
+ }
+ NotifyListener(PeriodicChecker::kVersionFetchTaskMessageId, success);
+}
+
+// Internal
+bool VersionFetchTask::ExtractVersionAndDownloadUrl(const std::string16& xml) {
+ CComPtr<IXMLDOMDocument2> document;
+ // Note that CoInitializeEx is called by the parent class.
+ if (FAILED(document.CoCreateInstance(
+ CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER))) {
+ return false;
+ }
+ ASSERT(document);
+ document->put_async(VARIANT_FALSE);
+ VARIANT_BOOL success;
+ // Load the document
+ if (FAILED(document->loadXML(const_cast<BSTR>(xml.c_str()), &success)) ||
+ success == VARIANT_FALSE) {
+ return false;
+ }
+ // Set the query language and namespace
+ VARIANT var = {0};
+ CComBSTR bstr(kNamespace);
+ bstr.CopyTo(&var);
+ HRESULT hr = document->setProperty(const_cast<BSTR>(kNamespaceProperty),
var);
+ VariantClear(&var);
+ if (FAILED(hr)) return false;
+
+ bstr = kQueryLanguage; // this frees the old string stored by bstr.
+ bstr.CopyTo(&var);
+ hr = document->setProperty(const_cast<BSTR>(kQueryLanguageProperty), var);
+ VariantClear(&var);
+ if (FAILED(hr)) return false;
+
+ // Run the version query
+ IXMLDOMNodeList* node_list = NULL;
+ long number_of_nodes = 0; // get_length() needs a ptr to long
+ if (FAILED(document->selectNodes(const_cast<BSTR>(kVersionQuery),
+ &node_list)) ||
+ FAILED(node_list->get_length(&number_of_nodes))) {
+ return false;
+ }
+ // We expect 0 or 1 element, depending on whether an update is available.
+ // We return early if we get 0 elements (no updates available).
+ if (number_of_nodes == 0) return false;
+ ASSERT(number_of_nodes == 1);
+ IXMLDOMNode* node;
+ if (FAILED(node_list->get_item(0, &node))) {
+ return false;
+ }
+ BSTR version_text;
+ if (FAILED(node->get_text(&version_text))) {
+ return false;
+ }
+ latest_version_ = version_text;
+ // Hurray, done with the version. Now the update link.
+ number_of_nodes = 0;
+ if (FAILED(document->selectNodes(const_cast<BSTR>(kUpdateLinkQuery),
+ &node_list)) ||
+ FAILED(node_list->get_length(&number_of_nodes))) {
+ return false;
+ }
+ // We expect 0 or 1 element, depending on whether an update is available.
+ // We return early if we get 0 elements (no updates available).
+ if (number_of_nodes == 0) return false;
+ ASSERT(number_of_nodes == 1);
+ if (FAILED(node_list->get_item(0, &node))) {
+ return false;
+ }
+ BSTR update_link;
+ if (FAILED(node->get_text(&update_link))) {
+ return false;
+ }
+ url_ = update_link;
+ return true;
+}
====
//depot/googleclient/gears/opensource/gears/installer/iemobile/periodic_checker.h#1
-
c:\MyDocs\Gears1/googleclient/gears/opensource/gears/installer/iemobile/periodic_checker.h
====
# action=add type=text
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ googleclient/gears/opensource/gears/installer/iemobile/periodic_checker.h
2008-10-17 16:10:09.000000000 +0100
@@ -0,0 +1,132 @@
+// Copyright 2008, Google Inc.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
notice,
+// this list of conditions and the following disclaimer in the
documentation
+// and/or other materials provided with the distribution.
+// 3. Neither the name of Google Inc. nor the names of its contributors may be
+// used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SBUSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file defines the PeriodicChecker class. This class makes regular
+// requests to a server to check for upgrades available for the specified
+// application. On receiving a response from the server, this class parses the
+// response to extract the latest available version and its download URL. If a
+// new version is available, a callback is made to the listener with the
+// download URL of the new version.
+
+#ifndef GEARS_INSTALLER_IEMOBILE_PERIODIC_CHECKER_H__
+#define GEARS_INSTALLER_IEMOBILE_PERIODIC_CHECKER_H__
+
+#include <atlsync.h> // For CEvent
+#include <gears/base/common/string16.h>
+#include "gears/base/common/wince_compatibility.h"
+#include "gears/base/ie/atl_headers.h"
+
+// An implemnentation detail of PeriodicChecker.
+class VersionFetchTask;
+
+class PeriodicChecker : public CWindowImpl<PeriodicChecker> {
+ public:
+ class ListenerInterface {
+ public:
+ virtual void UpdateUrlAvailable(const std::string16 &url) = 0;
+ };
+
+ // Simple factory method.
+ static PeriodicChecker* CreateChecker();
+ // Initializes the checker and sets the desired times between update checks.
+ // Also sets the application ID sent to the server for update checks and the
+ // listener for callbacks.
+ bool Init(int first_period, int normal_period, int grace_period,
+ const std::string16 &application_id, ListenerInterface *listener);
+ // Starts the checker thread.
+ void Start();
+ // Stops the checker thread. Parmeter specifies whether this call should
block
+ // waiting for the checker to clean up. In general, specifying false here is
+ // dangerous. See CabUpdater::Stop for details of why this flag is required.
+ void Stop(bool wait_for_cleanup);
+ ~PeriodicChecker();
+
+ static const int kVersionFetchTaskMessageId = 0;
+
+ private:
+ // TODO(andreip): aggregate all Gears WM_USER messages in the same
+ // header to avoid overlap.
+ static const int kUpdateTaskMessageBase = WM_USER;
+ static const int WM_FETCH_TASK_COMPLETE =
+ kUpdateTaskMessageBase + kVersionFetchTaskMessageId;
+
+ // CWindowImpl
+ BEGIN_MSG_MAP(PeriodicChecker)
+ MESSAGE_HANDLER(WM_TIMER, OnTimer)
+ MESSAGE_HANDLER(WM_FETCH_TASK_COMPLETE, OnComplete)
+ END_MSG_MAP()
+
+ // Internal
+ PeriodicChecker();
+
+ // Message handlers.
+ LRESULT OnTimer(UINT message, WPARAM w, LPARAM l, BOOL& handled);
+ LRESULT OnComplete(UINT message, WPARAM success, LPARAM task, BOOL& handled);
+
+ // This message handler is different because it needs to be registered at
+ // runtime with RegisterWindowMessage (it's comming from the connection
+ // manager process and that API only exposes a string).
+ void OnConnectionStatusChanged();
+ // Thread entry.
+ static unsigned int _stdcall ThreadMain(void* checker);
+ // Runs the Windows message loop machinery (essentially a lot of
boilerplate).
+ void RunMessageLoop();
+ // Timer utilitiy.
+ void ResetTimer(int period);
+
+ // The delay before the first check.
+ int first_period_;
+ // The normal time interval between checks.
+ int normal_period_;
+ // The time interval to wait after a connection up event.
+ int grace_period_;
+ // The application ID to include in the server URL.
+ std::string16 application_id_;
+ // The listener for callbacks
+ ListenerInterface *listener_;
+ // Events used for shutting down.
+ CEvent stop_event_;
+ CEvent thread_complete_event_;
+#ifdef DEBUG
+ // Whether we should wait for the thread to clean up during shutdown.
+ bool wait_for_cleanup_;
+#endif
+ // The thread handle.
+ HANDLE thread_;
+ // The window handle.
+ HWND window_;
+ // The timer ID.
+ int timer_;
+ // The task responsible for doing the HTTP requests to upgrade URL.
+ VersionFetchTask *task_;
+ // Was this a normal timer event?
+ bool normal_timer_event_;
+ // The message ID used for listening to connection status events.
+ uint32 con_mgr_msg_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(PeriodicChecker);
+};
+
+#endif // GEARS_INSTALLER_IEMOBILE_PERIODIC_CHECKER_H__