• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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