1 /*
2 * Copyright 2022 Google LLC. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "CapoDetector.h"
17 #include <google/protobuf/message.h>
18 #include <google/protobuf/io/coded_stream.h>
19 #include <google/protobuf/io/zero_copy_stream_impl.h>
20
21 #include <log/log.h>
22
23 #ifdef LOG_TAG
24 #undef LOG_TAG
25 #define LOG_TAG "CapoDetector"
26 #endif
27
28 namespace android {
29 namespace chre {
30
31 namespace { // anonymous namespace for file-local definitions
32
33 /**
34 * Called when onConnected() to send NanoappList request.
35 */
requestNanoappList(SocketClient & client)36 void requestNanoappList(SocketClient &client) {
37 flatbuffers::FlatBufferBuilder builder;
38 HostProtocolHost::encodeNanoappListRequest(builder);
39 if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
40 ALOGE("Failed to send NanoappList request");
41 }
42 }
43
44 } // namespace
45
46 /**
47 * Called when initializing connection with CHRE socket.
48 */
start()49 sp<CapoDetector> CapoDetector::start() {
50 sp<CapoDetector> listener = new CapoDetector();
51 if (!listener->connectInBackground(kChreSocketName, listener)) {
52 ALOGE("Couldn't connect to CHRE socket");
53 return nullptr;
54 }
55 ALOGI("%s connect to CHRE socket.", __func__);
56
57 return listener;
58 }
59
60 /**
61 * Called when the socket is successfully (re-)connected.
62 * Reset the position and try to send NanoappList request.
63 */
onConnected()64 void CapoDetector::onConnected() {
65 flatbuffers::FlatBufferBuilder builder;
66
67 // Reset the last position type.
68 last_position_type_ = capo::PositionType::UNKNOWN;
69 requestNanoappList(*this);
70 }
71
72 /**
73 * Called when we have failed to (re-)connect the socket after many attempts
74 * and are giving up.
75 */
onConnectionAborted()76 void CapoDetector::onConnectionAborted() {
77 ALOGE("%s, Capo Aborting Connection!", __func__);
78 }
79
80 /**
81 * Invoked when the socket is disconnected, and this connection loss was not
82 * the result of an explicit call to disconnect().
83 * Reset the position while disconnecting.
84 */
85
onDisconnected()86 void CapoDetector::onDisconnected() {
87 last_position_type_ = capo::PositionType::UNKNOWN;
88 }
89
90 /**
91 * Decode unix socket msgs to CHRE messages, and call the appropriate
92 * callback depending on the CHRE message.
93 */
onMessageReceived(const void * data,size_t length)94 void CapoDetector::onMessageReceived(const void *data, size_t length) {
95 if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
96 ALOGE("Failed to decode message");
97 }
98 }
99
100 /**
101 * Listen for messages from capo nanoapp and handle the message.
102 */
handleNanoappMessage(const fbs::NanoappMessageT & message)103 void CapoDetector::handleNanoappMessage(const fbs::NanoappMessageT &message) {
104 ALOGI("%s, Id %" PRIu64 ", type %d, size %d", __func__, message.app_id, message.message_type,
105 static_cast<int>(message.message.size()));
106 // Exclude the message with unmatched nanoapp id.
107 if (message.app_id != kCapoNanoappId)
108 return;
109
110 // Handle the message with message_type.
111 switch (message.message_type) {
112 case capo::MessageType::ACK_NOTIFICATION: {
113 capo::AckNotification gd;
114 gd.set_notification_type(static_cast<capo::NotificationType>(message.message[1]));
115 ALOGD("%s, get notification event from capo nanoapp, type %d", __func__,
116 gd.notification_type());
117 break;
118 }
119 case capo::MessageType::POSITION_DETECTED: {
120 capo::PositionDetected gd;
121 gd.set_position_type(static_cast<capo::PositionType>(message.message[1]));
122 ALOGD("%s, get position event from capo nanoapp, type %d", __func__,
123 gd.position_type());
124
125 // Callback to function while getting carried position event.
126 if (callback_func_ != nullptr) {
127 last_position_type_ = gd.position_type();
128 ALOGD("%s, sent position type %d to callback function", __func__,
129 last_position_type_);
130 callback_func_(last_position_type_);
131 }
132 break;
133 }
134 default:
135 ALOGE("%s, get invalid message, type: %" PRIu32 ", from capo nanoapp.", __func__,
136 message.message_type);
137 break;
138 }
139 }
140
141 /**
142 * Handle the response of a NanoappList request.
143 * Ensure that capo nanoapp is running.
144 */
handleNanoappListResponse(const fbs::NanoappListResponseT & response)145 void CapoDetector::handleNanoappListResponse(const fbs::NanoappListResponseT &response) {
146 for (const std::unique_ptr<fbs::NanoappListEntryT> &nanoapp : response.nanoapps) {
147 if (nanoapp->app_id == kCapoNanoappId) {
148 if (nanoapp->enabled)
149 enable();
150 else
151 ALOGE("Capo nanoapp not enabled");
152 return;
153 }
154 }
155 ALOGE("Capo nanoapp not found");
156 }
157
158 /**
159 * Send enabling message to the nanoapp.
160 */
enable()161 void CapoDetector::enable() {
162 // Create CHRE message with serialized message
163 flatbuffers::FlatBufferBuilder builder, config_builder, force_builder;
164
165 auto config_data = std::make_unique<capo::ConfigureDetector_ConfigData>();
166 auto msg = std::make_unique<capo::ConfigureDetector>();
167
168 config_data->set_still_time_threshold_nanosecond(mCapoDetectorMDParameters.still_time_threshold_ns);
169 config_data->set_window_width_nanosecond(mCapoDetectorMDParameters.window_width_ns);
170 config_data->set_motion_confidence_threshold(mCapoDetectorMDParameters.motion_confidence_threshold);
171 config_data->set_still_confidence_threshold(mCapoDetectorMDParameters.still_confidence_threshold);
172 config_data->set_var_threshold(mCapoDetectorMDParameters.var_threshold);
173 config_data->set_var_threshold_delta(mCapoDetectorMDParameters.var_threshold_delta);
174
175 msg->set_allocated_config_data(config_data.release());
176
177 auto pb_size = msg->ByteSizeLong();
178 auto pb_data = std::make_unique<uint8_t[]>(pb_size);
179
180 if (!msg->SerializeToArray(pb_data.get(), pb_size)) {
181 ALOGE("Failed to serialize message.");
182 }
183
184 ALOGI("Configuring CapoDetector");
185 // Configure the detector from host-side
186 android::chre::HostProtocolHost::encodeNanoappMessage(
187 config_builder, getNanoppAppId(), capo::MessageType::CONFIGURE_DETECTOR, getHostEndPoint(),
188 pb_data.get(), pb_size);
189 ALOGI("Sending capo config message to Nanoapp, %" PRIu32 " bytes", config_builder.GetSize());
190 if (!sendMessage(config_builder.GetBufferPointer(), config_builder.GetSize())) {
191 ALOGE("Failed to send config event for capo nanoapp");
192 }
193
194 ALOGI("Enabling CapoDetector");
195 android::chre::HostProtocolHost::encodeNanoappMessage(
196 builder, getNanoppAppId(), capo::MessageType::ENABLE_DETECTOR, getHostEndPoint(),
197 /*messageData*/ nullptr, /*messageDataLenbuffer*/ 0);
198 ALOGI("Sending enable message to Nanoapp, %" PRIu32 " bytes", builder.GetSize());
199 if (!sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
200 ALOGE("Failed to send enable event for capo nanoapp");
201 }
202
203 ALOGI("Forcing CapoDetector to update state");
204 // Force an updated state upon connection
205 android::chre::HostProtocolHost::encodeNanoappMessage(
206 force_builder, getNanoppAppId(), capo::MessageType::FORCE_UPDATE, getHostEndPoint(),
207 /*messageData*/ nullptr, /*messageDataLenbuffer*/ 0);
208 ALOGI("Sending force-update message to Nanoapp, %" PRIu32 " bytes", force_builder.GetSize());
209 if (!sendMessage(force_builder.GetBufferPointer(), force_builder.GetSize())) {
210 ALOGE("Failed to send force-update event for capo nanoapp");
211 }
212 }
213
214 } // namespace chre
215 } // namespace android
216