• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
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 
17 #include "CapoDetector.h"
18 
19 #include <google/protobuf/io/coded_stream.h>
20 #include <google/protobuf/io/zero_copy_stream_impl.h>
21 #include <google/protobuf/message.h>
22 #include <log/log.h>
23 
24 #ifdef LOG_TAG
25 #undef LOG_TAG
26 #define LOG_TAG "CapoDetector"
27 #endif
28 
29 namespace android {
30 namespace chre {
31 
32 /**
33  * Called when initializing connection with CHRE socket.
34  */
start()35 sp<CapoDetector> CapoDetector::start() {
36     sp<CapoDetector> listener = new CapoDetector();
37     if (!listener->connectInBackground(kChreSocketName, listener)) {
38         ALOGE("Couldn't connect to CHRE socket");
39         return nullptr;
40     }
41     ALOGI("%s connect to CHRE socket.", __func__);
42 
43     return listener;
44 }
45 
46 /**
47  * Called when the socket is successfully (re-)connected.
48  * Reset the position and try to send NanoappList request.
49  */
onConnected()50 void CapoDetector::onConnected() {
51     flatbuffers::FlatBufferBuilder builder;
52 
53     // Reset the last position type.
54     last_position_type_ = capo::PositionType::UNKNOWN;
55 
56     HostProtocolHost::encodeNanoappListRequest(builder);
57     if (!sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
58         ALOGE("Failed to send NanoappList request");
59         // We don't return nullptr here so that we don't change the behavior
60     }
61 }
62 
63 /**
64  * Called when we have failed to (re-)connect the socket after many attempts
65  * and are giving up.
66  */
onConnectionAborted()67 void CapoDetector::onConnectionAborted() {
68     ALOGE("%s, Capo Aborting Connection!", __func__);
69 }
70 
71 /**
72  * Invoked when the socket is disconnected, and this connection loss was not
73  * the result of an explicit call to disconnect().
74  * Reset the position while disconnecting.
75  */
76 
onDisconnected()77 void CapoDetector::onDisconnected() {
78     last_position_type_ = capo::PositionType::UNKNOWN;
79 }
80 
81 /**
82  * Decode unix socket msgs to CHRE messages, and call the appropriate
83  * callback depending on the CHRE message.
84  */
onMessageReceived(const void * data,size_t length)85 void CapoDetector::onMessageReceived(const void *data, size_t length) {
86     if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
87         ALOGE("Failed to decode message");
88     }
89 }
90 
91 /**
92  * Listen for messages from capo nanoapp and handle the message.
93  */
handleNanoappMessage(const fbs::NanoappMessageT & message)94 void CapoDetector::handleNanoappMessage(const fbs::NanoappMessageT &message) {
95     ALOGI("%s, Id %" PRIu64 ", type %d, size %d", __func__, message.app_id, message.message_type,
96           static_cast<int>(message.message.size()));
97     // Exclude the message with unmatched nanoapp id.
98     if (message.app_id != kCapoNanoappId)
99         return;
100 
101     // Handle the message with message_type.
102     switch (message.message_type) {
103         case capo::MessageType::ACK_NOTIFICATION: {
104             capo::AckNotification gd;
105             gd.set_notification_type(static_cast<capo::NotificationType>(message.message[1]));
106             ALOGD("%s, get notification event from capo nanoapp, type %d", __func__,
107                   gd.notification_type());
108             break;
109         }
110         case capo::MessageType::POSITION_DETECTED: {
111             uint8_t position;
112             uint32_t time;
113             {
114                 std::lock_guard<std::mutex> lock(mCapoMutex);
115                 capo::PositionDetected gd;
116                 time = getCurrentTimeInMs();
117                 gd.set_position_type(static_cast<capo::PositionType>(message.message[1]));
118                 ALOGD("CapoDetector: [%u] get position event from capo nanoapp, from %d to %d",
119                       time, last_position_type_, gd.position_type());
120 
121                 // Record the last moment we were in FACE_UP state
122                 if (last_position_type_ == capo::PositionType::ON_TABLE_FACE_UP ||
123                     gd.position_type() == capo::PositionType::ON_TABLE_FACE_UP) {
124                     mLastFaceUpEvent = time;
125                 }
126                 last_position_type_ = gd.position_type();
127                 position = last_position_type_;
128             }
129             // Callback to function while getting carried position event.
130             if (callback_func_ != nullptr) {
131                 ALOGD("%s, sent position type %d to callback function", __func__,
132                       last_position_type_);
133                 callback_func_(last_position_type_);
134             }
135             break;
136         }
137         default:
138             ALOGE("%s, get invalid message, type: %" PRIu32 ", from capo nanoapp.", __func__,
139                   message.message_type);
140             break;
141     }
142 }
143 
144 /**
145  * Handle the response of a NanoappList request.
146  * Ensure that capo nanoapp is running.
147  */
handleNanoappListResponse(const fbs::NanoappListResponseT & response)148 void CapoDetector::handleNanoappListResponse(const fbs::NanoappListResponseT &response) {
149     for (const std::unique_ptr<fbs::NanoappListEntryT> &nanoapp : response.nanoapps) {
150         if (nanoapp->app_id == kCapoNanoappId) {
151             if (nanoapp->enabled)
152                 enable();
153             else
154                 ALOGE("Capo nanoapp not enabled");
155             return;
156         }
157     }
158     ALOGE("Capo nanoapp not found");
159 }
160 
161 /**
162  * Send enabling message to the nanoapp.
163  */
enable()164 void CapoDetector::enable() {
165     // Create CHRE message with serialized message
166     flatbuffers::FlatBufferBuilder builder, config_builder, force_builder;
167 
168     auto config_data = std::make_unique<capo::ConfigureDetector_ConfigData>();
169     auto msg = std::make_unique<capo::ConfigureDetector>();
170 
171     config_data->set_still_time_threshold_nanosecond(
172             mCapoDetectorMDParameters.still_time_threshold_ns);
173     config_data->set_window_width_nanosecond(mCapoDetectorMDParameters.window_width_ns);
174     config_data->set_motion_confidence_threshold(
175             mCapoDetectorMDParameters.motion_confidence_threshold);
176     config_data->set_still_confidence_threshold(
177             mCapoDetectorMDParameters.still_confidence_threshold);
178     config_data->set_var_threshold(mCapoDetectorMDParameters.var_threshold);
179     config_data->set_var_threshold_delta(mCapoDetectorMDParameters.var_threshold_delta);
180 
181     msg->set_allocated_config_data(config_data.release());
182 
183     auto pb_size = msg->ByteSizeLong();
184     auto pb_data = std::make_unique<uint8_t[]>(pb_size);
185 
186     if (!msg->SerializeToArray(pb_data.get(), pb_size)) {
187         ALOGE("Failed to serialize message.");
188     }
189 
190     ALOGI("Configuring CapoDetector");
191     // Configure the detector from host-side
192     ::android::chre::HostProtocolHost::encodeNanoappMessage(
193             config_builder, getNanoppAppId(), capo::MessageType::CONFIGURE_DETECTOR,
194             getHostEndPoint(), pb_data.get(), pb_size);
195     ALOGI("Sending capo config message to Nanoapp, %" PRIu32 " bytes", config_builder.GetSize());
196     if (!sendMessage(config_builder.GetBufferPointer(), config_builder.GetSize())) {
197         ALOGE("Failed to send config event for capo nanoapp");
198     }
199 
200     ALOGI("Enabling CapoDetector");
201     ::android::chre::HostProtocolHost::encodeNanoappMessage(
202             builder, getNanoppAppId(), capo::MessageType::ENABLE_DETECTOR, getHostEndPoint(),
203             /*messageData*/ nullptr, /*messageDataLenbuffer*/ 0);
204     ALOGI("Sending enable message to Nanoapp, %" PRIu32 " bytes", builder.GetSize());
205     if (!sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
206         ALOGE("Failed to send enable event for capo nanoapp");
207     }
208 
209     ALOGI("Forcing CapoDetector to update state");
210     // Force an updated state upon connection
211     ::android::chre::HostProtocolHost::encodeNanoappMessage(
212             force_builder, getNanoppAppId(), capo::MessageType::FORCE_UPDATE, getHostEndPoint(),
213             /*messageData*/ nullptr, /*messageDataLenbuffer*/ 0);
214     ALOGI("Sending force-update message to Nanoapp, %" PRIu32 " bytes", force_builder.GetSize());
215     if (!sendMessage(force_builder.GetBufferPointer(), force_builder.GetSize())) {
216         ALOGE("Failed to send force-update event for capo nanoapp");
217     }
218 }
219 
220 /**
221  * Method for gathering the position and time tuple simultaneously to avoid any
222  * concurrency issues.
223  */
getCarriedPositionInfo(uint8_t * position,uint32_t * time)224 void CapoDetector::getCarriedPositionInfo(uint8_t *position, uint32_t *time) {
225     std::lock_guard<std::mutex> lock(mCapoMutex);
226     if (position)
227         *position = last_position_type_;
228     if (time)
229         *time = mLastFaceUpEvent;
230 }
231 
232 }  // namespace chre
233 }  // namespace android
234