device_google_lynx/vibrator/cs40l26/CapoDetector.cpp
Chris Paulo ad95139b97 [DO NOT MERGE] lynx/vibrator: Fix Capodetector on AoC restart
Update pointers used in protobuf interface for configuring the detector.
When AoC has an SSR, it causes CapoDetector to go down by null pointer
dereference.

Bug: 261349596
Test: Verified 10x forced AoC SSR - adb shell 'echo mem dump 0 > /dev/acd-debug'
Change-Id: I48d94b721fc3ba689a48e415d04fa4152f4f8865
Signed-off-by: Chris Paulo <chrispaulo@google.com>
2022-12-29 02:23:42 +00:00

215 lines
7.7 KiB
C++

/*
* Copyright 2022 Google LLC. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "CapoDetector.h"
#include <google/protobuf/message.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <log/log.h>
#ifdef LOG_TAG
#undef LOG_TAG
#define LOG_TAG "CapoDetector"
#endif
namespace android {
namespace chre {
namespace { // anonymous namespace for file-local definitions
/**
* Called when onConnected() to send NanoappList request.
*/
void requestNanoappList(SocketClient &client) {
flatbuffers::FlatBufferBuilder builder;
HostProtocolHost::encodeNanoappListRequest(builder);
if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
ALOGE("Failed to send NanoappList request");
}
}
} // namespace
/**
* Called when initializing connection with CHRE socket.
*/
sp<CapoDetector> CapoDetector::start() {
sp<CapoDetector> listener = new CapoDetector();
if (!listener->connectInBackground(kChreSocketName, listener)) {
ALOGE("Couldn't connect to CHRE socket");
return nullptr;
}
ALOGI("%s connect to CHRE socket.", __func__);
return listener;
}
/**
* Called when the socket is successfully (re-)connected.
* Reset the position and try to send NanoappList request.
*/
void CapoDetector::onConnected() {
flatbuffers::FlatBufferBuilder builder;
// Reset the last position type.
last_position_type_ = capo::PositionType::UNKNOWN;
requestNanoappList(*this);
}
/**
* Called when we have failed to (re-)connect the socket after many attempts
* and are giving up.
*/
void CapoDetector::onConnectionAborted() {
ALOGE("%s, Capo Aborting Connection!", __func__);
}
/**
* Invoked when the socket is disconnected, and this connection loss was not
* the result of an explicit call to disconnect().
* Reset the position while disconnecting.
*/
void CapoDetector::onDisconnected() {
last_position_type_ = capo::PositionType::UNKNOWN;
}
/**
* Decode unix socket msgs to CHRE messages, and call the appropriate
* callback depending on the CHRE message.
*/
void CapoDetector::onMessageReceived(const void *data, size_t length) {
if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
ALOGE("Failed to decode message");
}
}
/**
* Listen for messages from capo nanoapp and handle the message.
*/
void CapoDetector::handleNanoappMessage(const fbs::NanoappMessageT &message) {
ALOGI("%s, Id %" PRIu64 ", type %d, size %d", __func__, message.app_id, message.message_type,
static_cast<int>(message.message.size()));
// Exclude the message with unmatched nanoapp id.
if (message.app_id != kCapoNanoappId)
return;
// Handle the message with message_type.
switch (message.message_type) {
case capo::MessageType::ACK_NOTIFICATION: {
capo::AckNotification gd;
gd.set_notification_type(static_cast<capo::NotificationType>(message.message[1]));
ALOGD("%s, get notification event from capo nanoapp, type %d", __func__,
gd.notification_type());
break;
}
case capo::MessageType::POSITION_DETECTED: {
capo::PositionDetected gd;
gd.set_position_type(static_cast<capo::PositionType>(message.message[1]));
ALOGD("%s, get position event from capo nanoapp, type %d", __func__,
gd.position_type());
// Callback to function while getting carried position event.
if (callback_func_ != nullptr) {
last_position_type_ = gd.position_type();
ALOGD("%s, sent position type %d to callback function", __func__,
last_position_type_);
callback_func_(last_position_type_);
}
break;
}
default:
ALOGE("%s, get invalid message, type: %" PRIu32 ", from capo nanoapp.", __func__,
message.message_type);
break;
}
}
/**
* Handle the response of a NanoappList request.
* Ensure that capo nanoapp is running.
*/
void CapoDetector::handleNanoappListResponse(const fbs::NanoappListResponseT &response) {
for (const std::unique_ptr<fbs::NanoappListEntryT> &nanoapp : response.nanoapps) {
if (nanoapp->app_id == kCapoNanoappId) {
if (nanoapp->enabled)
enable();
else
ALOGE("Capo nanoapp not enabled");
return;
}
}
ALOGE("Capo nanoapp not found");
}
/**
* Send enabling message to the nanoapp.
*/
void CapoDetector::enable() {
// Create CHRE message with serialized message
flatbuffers::FlatBufferBuilder builder, config_builder, force_builder;
auto config_data = std::make_unique<capo::ConfigureDetector_ConfigData>();
auto msg = std::make_unique<capo::ConfigureDetector>();
config_data->set_still_time_threshold_nanosecond(mCapoDetectorMDParameters.still_time_threshold_ns);
config_data->set_window_width_nanosecond(mCapoDetectorMDParameters.window_width_ns);
config_data->set_motion_confidence_threshold(mCapoDetectorMDParameters.motion_confidence_threshold);
config_data->set_still_confidence_threshold(mCapoDetectorMDParameters.still_confidence_threshold);
config_data->set_var_threshold(mCapoDetectorMDParameters.var_threshold);
config_data->set_var_threshold_delta(mCapoDetectorMDParameters.var_threshold_delta);
msg->set_allocated_config_data(config_data.release());
auto pb_size = msg->ByteSizeLong();
auto pb_data = std::make_unique<uint8_t[]>(pb_size);
if (!msg->SerializeToArray(pb_data.get(), pb_size)) {
ALOGE("Failed to serialize message.");
}
ALOGI("Configuring CapoDetector");
// Configure the detector from host-side
android::chre::HostProtocolHost::encodeNanoappMessage(
config_builder, getNanoppAppId(), capo::MessageType::CONFIGURE_DETECTOR, getHostEndPoint(),
pb_data.get(), pb_size);
ALOGI("Sending capo config message to Nanoapp, %" PRIu32 " bytes", config_builder.GetSize());
if (!sendMessage(config_builder.GetBufferPointer(), config_builder.GetSize())) {
ALOGE("Failed to send config event for capo nanoapp");
}
ALOGI("Enabling CapoDetector");
android::chre::HostProtocolHost::encodeNanoappMessage(
builder, getNanoppAppId(), capo::MessageType::ENABLE_DETECTOR, getHostEndPoint(),
/*messageData*/ nullptr, /*messageDataLenbuffer*/ 0);
ALOGI("Sending enable message to Nanoapp, %" PRIu32 " bytes", builder.GetSize());
if (!sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
ALOGE("Failed to send enable event for capo nanoapp");
}
ALOGI("Forcing CapoDetector to update state");
// Force an updated state upon connection
android::chre::HostProtocolHost::encodeNanoappMessage(
force_builder, getNanoppAppId(), capo::MessageType::FORCE_UPDATE, getHostEndPoint(),
/*messageData*/ nullptr, /*messageDataLenbuffer*/ 0);
ALOGI("Sending force-update message to Nanoapp, %" PRIu32 " bytes", force_builder.GetSize());
if (!sendMessage(force_builder.GetBufferPointer(), force_builder.GetSize())) {
ALOGE("Failed to send force-update event for capo nanoapp");
}
}
} // namespace chre
} // namespace android