Skip to content
This repository was archived by the owner on Jan 16, 2024. It is now read-only.

Commit f2dab7e

Browse files
Version 1.23.0 alexa-client-sdk
Changes in this update: Feature enhancements, updates, and resolved issues from all releases are available on the [Amazon developer portal](https://developer.amazon.com/docs/alexa/avs-device-sdk/release-notes.html)
1 parent 8e77a64 commit f2dab7e

File tree

370 files changed

+8376
-2860
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

370 files changed

+8376
-2860
lines changed

ACL/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
22
project(ACL LANGUAGES CXX)
33

4-
include(../build/BuildDefaults.cmake)
4+
include(${AVS_CMAKE_BUILD}/BuildDefaults.cmake)
55

66
add_subdirectory("src")
77
add_subdirectory("test")

ACL/include/ACL/AVSConnectionManager.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,14 @@ class AVSConnectionManager
176176

177177
void receive(const std::string& contextId, const std::string& message) override;
178178

179+
std::shared_ptr<MessageRouterInterface> getMessageRouter() const;
180+
179181
/// Mutex to serialize access to @c m_isEnabled
180182
std::mutex m_isEnabledMutex;
181183

184+
/// Mutex to serialize access to @c m_messageRouter
185+
mutable std::mutex m_messageRouterMutex;
186+
182187
/// Internal state to indicate if the Connection object is enabled for making an AVS connection.
183188
bool m_isEnabled;
184189

ACL/include/ACL/Transport/MessageRequestHandler.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <AVSCommon/AVS/Attachment/AttachmentManagerInterface.h>
2222
#include <AVSCommon/AVS/MessageRequest.h>
2323
#include <AVSCommon/SDKInterfaces/EventTracerInterface.h>
24+
#include <AVSCommon/SDKInterfaces/MessageRequestObserverInterface.h>
2425
#include <AVSCommon/Utils/Power/PowerResource.h>
2526
#include <AVSCommon/Utils/HTTP2/HTTP2MimeRequestSourceInterface.h>
2627
#include <AVSCommon/Utils/Metrics/MetricRecorderInterface.h>
@@ -142,6 +143,9 @@ class MessageRequestHandler
142143

143144
/// The reference to @c PowerResource to prevent device from going into LPM.
144145
std::shared_ptr<avsCommon::utils::power::PowerResource> m_powerResource;
146+
147+
/// Status to be reported back to the @c MessageRequest.
148+
avsCommon::sdkInterfaces::MessageRequestObserverInterface::Status m_resultStatus;
145149
};
146150

147151
} // namespace acl

ACL/src/AVSConnectionManager.cpp

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,21 +122,37 @@ void AVSConnectionManager::doShutdown() {
122122
std::lock_guard<std::mutex> lock{m_messageObserverMutex};
123123
m_messageObservers.clear();
124124
}
125+
std::unique_lock<std::mutex> lock{m_messageRouterMutex};
126+
/* There is still a potential deadlock if the reset of m_messageRouter triggers a delete of the message router,
127+
and that delete blocks on code that could call back into AVSConnectionManager and try to acquire that new mutex.
128+
We can get around this by having doShutdown() swap m_messageRouter with a local variable while holding the lock,
129+
and then resetting the local variable after new mutex is released.
130+
*/
131+
auto messageRouter = m_messageRouter;
125132
m_messageRouter.reset();
133+
lock.unlock();
134+
135+
messageRouter.reset();
126136
}
127137

128138
void AVSConnectionManager::enable() {
129139
std::lock_guard<std::mutex> lock(m_isEnabledMutex);
130140
ACSDK_DEBUG5(LX(__func__));
131141
m_isEnabled = true;
132-
m_messageRouter->enable();
142+
auto messageRouter = getMessageRouter();
143+
if (messageRouter) {
144+
messageRouter->enable();
145+
}
133146
}
134147

135148
void AVSConnectionManager::disable() {
136149
std::lock_guard<std::mutex> lock(m_isEnabledMutex);
137150
ACSDK_DEBUG5(LX(__func__));
138151
m_isEnabled = false;
139-
m_messageRouter->disable();
152+
auto messageRouter = getMessageRouter();
153+
if (messageRouter) {
154+
messageRouter->disable();
155+
}
140156
}
141157

142158
bool AVSConnectionManager::isEnabled() {
@@ -148,39 +164,76 @@ void AVSConnectionManager::reconnect() {
148164
std::lock_guard<std::mutex> lock(m_isEnabledMutex);
149165
ACSDK_DEBUG5(LX(__func__).d("isEnabled", m_isEnabled));
150166
if (m_isEnabled) {
151-
m_messageRouter->disable();
152-
m_messageRouter->enable();
167+
auto messageRouter = getMessageRouter();
168+
if (messageRouter) {
169+
messageRouter->disable();
170+
messageRouter->enable();
171+
}
153172
}
154173
}
155174

156175
void AVSConnectionManager::sendMessage(std::shared_ptr<avsCommon::avs::MessageRequest> request) {
157-
m_messageRouter->sendMessage(request);
176+
auto messageRouter = getMessageRouter();
177+
if (messageRouter) {
178+
messageRouter->sendMessage(request);
179+
} else {
180+
ACSDK_WARN(LX("sendMessageFailed")
181+
.d("reason", "nullMessageRouter")
182+
.m("setting status for request to NOT_CONNECTED")
183+
.d("request", request->getJsonContent()));
184+
request->sendCompleted(MessageRequestObserverInterface::Status::NOT_CONNECTED);
185+
}
158186
}
159187

160188
bool AVSConnectionManager::isConnected() const {
161-
return m_messageRouter->getConnectionStatus().first == ConnectionStatusObserverInterface::Status::CONNECTED;
189+
auto messageRouter = getMessageRouter();
190+
if (messageRouter) {
191+
return messageRouter->getConnectionStatus().first == ConnectionStatusObserverInterface::Status::CONNECTED;
192+
}
193+
return false;
162194
}
163195

164196
void AVSConnectionManager::onWakeConnectionRetry() {
165197
ACSDK_DEBUG9(LX(__func__));
166-
m_messageRouter->onWakeConnectionRetry();
198+
auto messageRouter = getMessageRouter();
199+
if (messageRouter) {
200+
messageRouter->onWakeConnectionRetry();
201+
} else {
202+
ACSDK_WARN(LX("onWakeConnectionRetryFailed").d("reason", "nullMessageRouter"));
203+
}
167204
}
168205

169206
void AVSConnectionManager::setAVSGateway(const std::string& avsGateway) {
170-
m_messageRouter->setAVSGateway(avsGateway);
207+
auto messageRouter = getMessageRouter();
208+
if (messageRouter) {
209+
messageRouter->setAVSGateway(avsGateway);
210+
} else {
211+
ACSDK_WARN(LX("setAVSGatewayFailed").d("reason", "nullMessageRouter"));
212+
}
171213
}
172214

173215
std::string AVSConnectionManager::getAVSGateway() const {
174-
return m_messageRouter->getAVSGateway();
216+
auto messageRouter = getMessageRouter();
217+
if (messageRouter) {
218+
return messageRouter->getAVSGateway();
219+
} else {
220+
ACSDK_WARN(LX("getAVSGatewayFailed").d("reason", "nullMessageRouter"));
221+
}
222+
return "";
175223
}
176224

177225
void AVSConnectionManager::onConnectionStatusChanged(bool connected) {
178226
ACSDK_DEBUG5(LX(__func__).d("connected", connected).d("isEnabled", m_isEnabled));
179227
if (m_isEnabled) {
180-
if (connected) {
181-
m_messageRouter->onWakeConnectionRetry();
228+
auto messageRouter = getMessageRouter();
229+
if (messageRouter) {
230+
if (connected) {
231+
messageRouter->onWakeConnectionRetry();
232+
} else {
233+
messageRouter->onWakeVerifyConnectivity();
234+
}
182235
} else {
183-
m_messageRouter->onWakeVerifyConnectivity();
236+
ACSDK_WARN(LX("onConnectionStatusChangedFailed").d("reason", "nullMessageRouter"));
184237
}
185238
}
186239
}
@@ -228,5 +281,10 @@ void AVSConnectionManager::receive(const std::string& contextId, const std::stri
228281
}
229282
}
230283

284+
std::shared_ptr<MessageRouterInterface> AVSConnectionManager::getMessageRouter() const {
285+
std::lock_guard<std::mutex> lock{m_messageRouterMutex};
286+
return m_messageRouter;
287+
}
288+
231289
} // namespace acl
232290
} // namespace alexaClientSDK

ACL/src/Transport/MessageRequestHandler.cpp

Lines changed: 53 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ using namespace avsCommon::utils::power;
4343
const static std::string AVS_EVENT_URL_PATH_EXTENSION = "/v20160207/events";
4444

4545
/// Boundary for mime encoded requests
46-
const static std::string MIME_BOUNDARY = "WhooHooZeerOoonie!";
46+
const static std::string MIME_BOUNDARY = "WhooHooZeerOoonie=";
4747

4848
/// Timeout for transmission of data on a given stream
4949
static const std::chrono::seconds STREAM_PROGRESS_TIMEOUT = std::chrono::seconds(15);
@@ -200,7 +200,8 @@ MessageRequestHandler::MessageRequestHandler(
200200
m_wasMessageRequestAcknowledgeReported{false},
201201
m_wasMessageRequestFinishedReported{false},
202202
m_responseCode{0},
203-
m_powerResource{powerResource} {
203+
m_powerResource{powerResource},
204+
m_resultStatus{MessageRequestObserverInterface::Status::PENDING} {
204205
ACSDK_DEBUG7(LX(__func__).d("context", context.get()).d("messageRequest", messageRequest.get()));
205206

206207
if (m_powerResource) {
@@ -324,15 +325,37 @@ void MessageRequestHandler::onActivity() {
324325
bool MessageRequestHandler::onReceiveResponseCode(long responseCode) {
325326
ACSDK_DEBUG7(LX(__func__).d("responseCode", responseCode));
326327

327-
// TODO ACSDK-1839: Provide MessageRequestObserverInterface immediate notification of receipt of response code.
328-
329328
reportMessageRequestAcknowledged();
330329

331330
if (HTTPResponseCode::CLIENT_ERROR_FORBIDDEN == intToHTTPResponseCode(responseCode)) {
332331
m_context->onForbidden(m_authToken);
333332
}
334333

335334
m_responseCode = responseCode;
335+
336+
// Map HTTPResponseCode values to MessageRequestObserverInterface::Status values.
337+
static const std::unordered_map<long, MessageRequestObserverInterface::Status> responseToResult = {
338+
{HTTPResponseCode::HTTP_RESPONSE_CODE_UNDEFINED, MessageRequestObserverInterface::Status::INTERNAL_ERROR},
339+
{HTTPResponseCode::SUCCESS_OK, MessageRequestObserverInterface::Status::SUCCESS},
340+
{HTTPResponseCode::SUCCESS_ACCEPTED, MessageRequestObserverInterface::Status::SUCCESS_ACCEPTED},
341+
{HTTPResponseCode::SUCCESS_NO_CONTENT, MessageRequestObserverInterface::Status::SUCCESS_NO_CONTENT},
342+
{HTTPResponseCode::CLIENT_ERROR_BAD_REQUEST, MessageRequestObserverInterface::Status::BAD_REQUEST},
343+
{HTTPResponseCode::CLIENT_ERROR_FORBIDDEN, MessageRequestObserverInterface::Status::INVALID_AUTH},
344+
{HTTPResponseCode::CLIENT_ERROR_THROTTLING_EXCEPTION, MessageRequestObserverInterface::Status::THROTTLED},
345+
{HTTPResponseCode::SERVER_ERROR_INTERNAL, MessageRequestObserverInterface::Status::SERVER_INTERNAL_ERROR_V2},
346+
{HTTPResponseCode::SERVER_UNAVAILABLE, MessageRequestObserverInterface::Status::REFUSED}};
347+
348+
auto responseIterator = responseToResult.find(m_responseCode);
349+
if (responseIterator != responseToResult.end()) {
350+
m_resultStatus = responseIterator->second;
351+
} else {
352+
m_resultStatus = MessageRequestObserverInterface::Status::SERVER_OTHER_ERROR;
353+
}
354+
355+
ACSDK_DEBUG7(LX("responseCodeTranslated").d("responseStatus", m_resultStatus));
356+
357+
m_messageRequest->responseStatusReceived(m_resultStatus);
358+
336359
return true;
337360
}
338361

@@ -350,51 +373,35 @@ void MessageRequestHandler::onResponseFinished(HTTP2ResponseFinishedStatus statu
350373
m_messageRequest->exceptionReceived(nonMimeBody);
351374
}
352375

353-
// Hash to allow use of HTTP2ResponseFinishedStatus as the key in an unordered_map.
354-
struct statusHash {
355-
size_t operator()(const HTTP2ResponseFinishedStatus& key) const {
356-
return static_cast<size_t>(key);
357-
}
358-
};
359-
360-
// Mapping HTTP2ResponseFinishedStatus to a MessageRequestObserverInterface::Status. Note that no mapping is
361-
// provided from the COMPLETE status so that the logic below falls through to map the HTTPResponseCode value
362-
// from the completed requests to the appropriate MessageRequestObserverInterface value.
363-
static const std::unordered_map<HTTP2ResponseFinishedStatus, MessageRequestObserverInterface::Status, statusHash>
364-
statusToResult = {
365-
{HTTP2ResponseFinishedStatus::INTERNAL_ERROR, MessageRequestObserverInterface::Status::INTERNAL_ERROR},
366-
{HTTP2ResponseFinishedStatus::CANCELLED, MessageRequestObserverInterface::Status::CANCELED},
367-
{HTTP2ResponseFinishedStatus::TIMEOUT, MessageRequestObserverInterface::Status::TIMEDOUT}};
368-
369-
// Map HTTPResponseCode values to MessageRequestObserverInterface::Status values.
370-
static const std::unordered_map<long, MessageRequestObserverInterface::Status> responseToResult = {
371-
{HTTPResponseCode::HTTP_RESPONSE_CODE_UNDEFINED, MessageRequestObserverInterface::Status::INTERNAL_ERROR},
372-
{HTTPResponseCode::SUCCESS_OK, MessageRequestObserverInterface::Status::SUCCESS},
373-
{HTTPResponseCode::SUCCESS_ACCEPTED, MessageRequestObserverInterface::Status::SUCCESS_ACCEPTED},
374-
{HTTPResponseCode::SUCCESS_NO_CONTENT, MessageRequestObserverInterface::Status::SUCCESS_NO_CONTENT},
375-
{HTTPResponseCode::CLIENT_ERROR_BAD_REQUEST, MessageRequestObserverInterface::Status::BAD_REQUEST},
376-
{HTTPResponseCode::CLIENT_ERROR_FORBIDDEN, MessageRequestObserverInterface::Status::INVALID_AUTH},
377-
{HTTPResponseCode::CLIENT_ERROR_THROTTLING_EXCEPTION, MessageRequestObserverInterface::Status::THROTTLED},
378-
{HTTPResponseCode::SERVER_ERROR_INTERNAL, MessageRequestObserverInterface::Status::SERVER_INTERNAL_ERROR_V2},
379-
{HTTPResponseCode::SERVER_UNAVAILABLE, MessageRequestObserverInterface::Status::REFUSED}};
380-
381-
auto result = MessageRequestObserverInterface::Status::INTERNAL_ERROR;
376+
bool receivedResponseCode = MessageRequestObserverInterface::Status::PENDING != m_resultStatus;
377+
378+
// Map HTTP2ResponseFinishedStatus to a MessageRequestObserverInterface::Status.
379+
380+
switch (status) {
381+
case HTTP2ResponseFinishedStatus::COMPLETE:
382+
if (!receivedResponseCode) {
383+
m_resultStatus = MessageRequestObserverInterface::Status::INTERNAL_ERROR;
384+
}
385+
break;
386+
case HTTP2ResponseFinishedStatus::TIMEOUT:
387+
m_resultStatus = MessageRequestObserverInterface::Status::TIMEDOUT;
388+
break;
389+
case HTTP2ResponseFinishedStatus::CANCELLED:
390+
m_resultStatus = MessageRequestObserverInterface::Status::CANCELED;
391+
break;
392+
case HTTP2ResponseFinishedStatus::INTERNAL_ERROR:
393+
m_resultStatus = MessageRequestObserverInterface::Status::INTERNAL_ERROR;
394+
break;
395+
default:
396+
ACSDK_ERROR(LX("unhandledHTTP2ResponseFinishedStatus").d("status", status));
397+
m_resultStatus = MessageRequestObserverInterface::Status::INTERNAL_ERROR;
398+
}
382399

383-
if (HTTP2ResponseFinishedStatus::COMPLETE == status) {
384-
auto responseIterator = responseToResult.find(m_responseCode);
385-
if (responseIterator != responseToResult.end()) {
386-
result = responseIterator->second;
387-
} else {
388-
result = MessageRequestObserverInterface::Status::SERVER_OTHER_ERROR;
389-
}
390-
} else {
391-
auto statusIterator = statusToResult.find(status);
392-
if (statusIterator != statusToResult.end()) {
393-
result = statusIterator->second;
394-
}
400+
if (!receivedResponseCode) {
401+
m_messageRequest->responseStatusReceived(m_resultStatus);
395402
}
396403

397-
m_messageRequest->sendCompleted(result);
404+
m_messageRequest->sendCompleted(m_resultStatus);
398405
}
399406

400407
} // namespace acl

ACL/src/Transport/MessageRouter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,13 @@ void MessageRouter::sendMessage(std::shared_ptr<MessageRequest> request) {
150150
ACSDK_ERROR(LX("sendFailed").d("reason", "nullRequest"));
151151
return;
152152
}
153+
154+
if (!request->isResolved()) {
155+
ACSDK_ERROR(LX("sendFailed").d("reason", "requestNotReady"));
156+
request->sendCompleted(MessageRequestObserverInterface::Status::BAD_REQUEST);
157+
return;
158+
}
159+
153160
std::unique_lock<std::mutex> lock{m_connectionMutex};
154161
if (m_activeTransport) {
155162
m_requestQueue->enqueueRequest(request);

ACL/test/Transport/HTTP2TransportTest.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -975,8 +975,14 @@ TEST_F(HTTP2TransportTest, test_onSendCompletedNotification) {
975975
// Check that we got the right onSendCompleted notifications.
976976
for (unsigned messageNum = 0; messageNum < messagesCount; messageNum++) {
977977
if (messageObservers[messageNum]->m_status.waitFor(RESPONSE_TIMEOUT)) {
978-
auto expectedMessageObserverStatus = std::get<2>(messageResponseMap[messageNum]);
979-
ASSERT_EQ(messageObservers[messageNum]->m_status.getValue(), expectedMessageObserverStatus);
978+
auto& item = messageResponseMap[messageNum];
979+
auto responseCode = std::get<0>(item);
980+
auto responseFinished = std::get<1>(item);
981+
auto expectedMessageObserverStatus = std::get<2>(item);
982+
ASSERT_EQ(messageObservers[messageNum]->m_status.getValue(), expectedMessageObserverStatus)
983+
<< "messageNum=" << messageNum << " responseCode=" << responseCode
984+
<< " responseFinished=" << responseFinished
985+
<< " expectedMessageObserverStatus=" << expectedMessageObserverStatus;
980986
}
981987
}
982988
}

ADSL/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
22
project(ADSL LANGUAGES CXX)
33

4-
include(../build/BuildDefaults.cmake)
4+
include(${AVS_CMAKE_BUILD}/BuildDefaults.cmake)
55

66
add_subdirectory("src")
77
add_subdirectory("test")

AFML/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
22
project(AFML LANGUAGES CXX)
33

4-
include(../build/BuildDefaults.cmake)
4+
include(${AVS_CMAKE_BUILD}/BuildDefaults.cmake)
55

66
add_subdirectory("src")
77
add_subdirectory("test")

0 commit comments

Comments
 (0)