OLD | NEW |
| (Empty) |
1 // Copyright 2009-2010 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 | |
16 #include "omaha/goopdate/app_state_checking_for_update.h" | |
17 #include "omaha/base/debug.h" | |
18 #include "omaha/base/error.h" | |
19 #include "omaha/base/logging.h" | |
20 #include "omaha/common/lang.h" | |
21 #include "omaha/common/update_response.h" | |
22 #include "omaha/goopdate/app_manager.h" | |
23 #include "omaha/goopdate/app_state_no_update.h" | |
24 #include "omaha/goopdate/app_state_update_available.h" | |
25 #include "omaha/goopdate/model.h" | |
26 #include "omaha/goopdate/server_resource.h" | |
27 #include "omaha/goopdate/string_formatter.h" | |
28 #include "omaha/goopdate/update_response_utils.h" | |
29 #include "omaha/goopdate/worker_metrics.h" | |
30 #include "omaha/goopdate/worker_utils.h" | |
31 | |
32 namespace omaha { | |
33 | |
34 namespace fsm { | |
35 | |
36 xml::UpdateResponseResult GetUpdateResponseResult( | |
37 const App* app, | |
38 const xml::UpdateResponse* update_response) { | |
39 ASSERT1(app); | |
40 ASSERT1(update_response); | |
41 | |
42 const CString language = app->app_bundle()->display_language(); | |
43 | |
44 xml::UpdateResponseResult update_response_result = | |
45 update_response_utils::GetResult(update_response, | |
46 app->app_guid_string(), | |
47 language); | |
48 | |
49 const bool is_omaha = !!::IsEqualGUID(kGoopdateGuid, app->app_guid()); | |
50 const bool has_update = update_response_result.first == S_OK && | |
51 app->is_update(); | |
52 | |
53 // Defer the update if the app is not Omaha, it has an update available, and | |
54 // an Omaha update is available at the same time. | |
55 if (!is_omaha && | |
56 has_update && | |
57 update_response_utils::IsOmahaUpdateAvailable(update_response)) { | |
58 StringFormatter formatter(language); | |
59 CString text; | |
60 VERIFY1(SUCCEEDED(formatter.LoadString(IDS_NO_UPDATE_RESPONSE, &text))); | |
61 update_response_result = std::make_pair(GOOPDATE_E_UPDATE_DEFERRED, text); | |
62 } | |
63 | |
64 return update_response_result; | |
65 } | |
66 | |
67 AppStateCheckingForUpdate::AppStateCheckingForUpdate() | |
68 : AppState(STATE_CHECKING_FOR_UPDATE), | |
69 update_response_(NULL) { | |
70 } | |
71 | |
72 // TODO(omaha3): Consider passing in an xml::response::App instead of a raw | |
73 // xml::UpdateResponse to this method. | |
74 void AppStateCheckingForUpdate::PostUpdateCheck( | |
75 App* app, | |
76 HRESULT update_check_result, | |
77 xml::UpdateResponse* update_response) { | |
78 CORE_LOG(L3, (_T("[AppStateCheckingForUpdate::PostUpdateCheck][0x%p]"), app)); | |
79 | |
80 ASSERT1(app); | |
81 ASSERT1(update_response); | |
82 | |
83 ASSERT1(app->model()->IsLockedByCaller()); | |
84 | |
85 update_response_ = update_response; | |
86 | |
87 const CString language = app->app_bundle()->display_language(); | |
88 | |
89 if (FAILED(update_check_result)) { | |
90 // TODO(omaha3): There is no guarantee that this is a actually network | |
91 // error. In Omaha 2, this was called much closer to the send. Making most | |
92 // errors, such as processing errors, app errors helps, but it could still | |
93 // be a parsing or other error. | |
94 CString error_message; | |
95 worker_utils::FormatMessageForNetworkError(update_check_result, | |
96 language, | |
97 &error_message); | |
98 | |
99 Error(app, ErrorContext(update_check_result), error_message); | |
100 return; | |
101 } | |
102 | |
103 PersistUpdateCheckSuccessfullySent(*app); | |
104 | |
105 const xml::UpdateResponseResult update_response_result( | |
106 GetUpdateResponseResult(app, update_response)); | |
107 | |
108 const HRESULT& code = update_response_result.first; | |
109 const CString& message = update_response_result.second; | |
110 | |
111 if (SUCCEEDED(code)) { | |
112 HandleUpdateAvailable(app, code, message); | |
113 } else if (code == GOOPDATE_E_UPDATE_DEFERRED) { | |
114 HandleUpdateDeferred(app, code, message); | |
115 } else if (code == GOOPDATE_E_NO_UPDATE_RESPONSE) { | |
116 HandleNoUpdate(app, code, message); | |
117 } else { | |
118 HandleErrorResponse(app, code, message); | |
119 } | |
120 } | |
121 | |
122 void AppStateCheckingForUpdate::HandleUpdateAvailable(App* app, | |
123 HRESULT code, | |
124 const CString& message) { | |
125 CORE_LOG(L3, (_T("[HandleUpdateAvailable][0x%p]"), app)); | |
126 | |
127 ASSERT1(app); | |
128 ASSERT1(SUCCEEDED(code)); | |
129 | |
130 UNREFERENCED_PARAMETER(code); | |
131 UNREFERENCED_PARAMETER(message); | |
132 | |
133 app->set_has_update_available(true); | |
134 | |
135 HRESULT hr = update_response_utils::BuildApp(update_response_, code, app); | |
136 if (FAILED(hr)) { | |
137 // Most of the errors that might actually be seen are likely to be due to | |
138 // response issues. Therefore, display a message about the server. | |
139 const CString language = app->app_bundle()->display_language(); | |
140 StringFormatter formatter(language); | |
141 CString error_message; | |
142 VERIFY1(SUCCEEDED(formatter.LoadString(IDS_UNKNOWN_APPLICATION, | |
143 &error_message))); | |
144 Error(app, ErrorContext(hr), error_message); | |
145 } | |
146 | |
147 const TCHAR* action = app->is_update() ? _T("update") : _T("install"); | |
148 app->LogTextAppendFormat(_T("Status=%s"), action); | |
149 | |
150 // Record the update available response regardless of how it is handled. | |
151 AppManager::Instance()->PersistSuccessfulUpdateCheckResponse(*app, true); | |
152 | |
153 if (app->is_update()) { | |
154 if (::IsEqualGUID(kGoopdateGuid, app->app_guid())) { | |
155 ++metric_worker_self_updates_available; | |
156 } else { | |
157 ++metric_worker_app_updates_available; | |
158 } | |
159 } | |
160 | |
161 ChangeState(app, new AppStateUpdateAvailable); | |
162 } | |
163 | |
164 void AppStateCheckingForUpdate::HandleUpdateDeferred(App* app, | |
165 HRESULT code, | |
166 const CString& message) { | |
167 CORE_LOG(L3, (_T("[HandleUpdateDeferred][0x%p]"), app)); | |
168 | |
169 ASSERT1(app); | |
170 ASSERT1(code == GOOPDATE_E_UPDATE_DEFERRED); | |
171 | |
172 ASSERT1(app->is_update()); | |
173 | |
174 app->SetNoUpdate(ErrorContext(code), message); | |
175 ChangeState(app, new AppStateNoUpdate); | |
176 } | |
177 | |
178 void AppStateCheckingForUpdate::HandleNoUpdate(App* app, | |
179 HRESULT code, | |
180 const CString& message) { | |
181 CORE_LOG(L3, (_T("[HandleNoUpdate][0x%p]"), app)); | |
182 ASSERT1(app); | |
183 ASSERT1(code == GOOPDATE_E_NO_UPDATE_RESPONSE); | |
184 | |
185 app->LogTextAppendFormat(_T("Status=no-update")); | |
186 | |
187 // For installs, no update is handled as an error. | |
188 if (!app->is_update()) { | |
189 Error(app, ErrorContext(code), message); | |
190 return; | |
191 } | |
192 | |
193 VERIFY1(SUCCEEDED(update_response_utils::BuildApp(update_response_, | |
194 code, | |
195 app))); | |
196 AppManager::Instance()->PersistSuccessfulUpdateCheckResponse(*app, false); | |
197 | |
198 app->SetNoUpdate(ErrorContext(S_OK), message); | |
199 ChangeState(app, new AppStateNoUpdate); | |
200 } | |
201 | |
202 void AppStateCheckingForUpdate::HandleErrorResponse(App* app, | |
203 HRESULT code, | |
204 const CString& message) { | |
205 CORE_LOG(L3, (_T("[HandleErrorResponse][0x%p]"), app)); | |
206 | |
207 ASSERT1(app); | |
208 ASSERT1(FAILED(code)); | |
209 | |
210 CString log_status; | |
211 switch (code) { | |
212 case GOOPDATE_E_NO_SERVER_RESPONSE: | |
213 log_status = _T("no-response-received"); | |
214 break; | |
215 case GOOPDATE_E_RESTRICTED_SERVER_RESPONSE: | |
216 log_status = _T("restricted"); | |
217 break; | |
218 case GOOPDATE_E_UNKNOWN_APP_SERVER_RESPONSE: | |
219 case GOOPDATE_E_OS_NOT_SUPPORTED: | |
220 case GOOPDATE_E_INTERNAL_ERROR_SERVER_RESPONSE: | |
221 case GOOPDATE_E_SERVER_RESPONSE_NO_HASH: | |
222 case GOOPDATE_E_SERVER_RESPONSE_UNSUPPORTED_PROTOCOL: | |
223 case GOOPDATE_E_UNKNOWN_SERVER_RESPONSE: | |
224 default: | |
225 log_status = _T("error"); | |
226 break; | |
227 } | |
228 | |
229 app->LogTextAppendFormat(_T("Status=%s, Code=0x%08x"), log_status, code); | |
230 | |
231 Error(app, ErrorContext(code), message); | |
232 } | |
233 | |
234 void AppStateCheckingForUpdate::PersistUpdateCheckSuccessfullySent( | |
235 const App& app) { | |
236 AppManager& app_manager = *AppManager::Instance(); | |
237 VERIFY1(SUCCEEDED(app_manager.PersistUpdateCheckSuccessfullySent( | |
238 app, update_response_->GetElapsedSecondsSinceDayStart()))); | |
239 | |
240 // Here we assume that some of the members in app object | |
241 // (days_since_last_active_ping_, days_since_last_roll_call_, iid_, did_run_) | |
242 // will not be used after the update check so there is no need to update them. | |
243 } | |
244 | |
245 } // namespace fsm | |
246 | |
247 } // namespace omaha | |
OLD | NEW |