1 /*
2 * Copyright (C) 2018 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 #include <pixelstats/DropDetect.h>
17
18 #include <chre/util/nanoapp/app_id.h>
19 #include <chre_host/host_protocol_host.h>
20 #include <chre_host/socket_client.h>
21
22 #include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
23 #include <pixelstats/StatsHelper.h>
24
25 #define LOG_TAG "pixelstats-vendor"
26 #include <log/log.h>
27
28 #include <inttypes.h>
29 #include <math.h>
30
31 using aidl::android::frameworks::stats::IStats;
32 using aidl::android::frameworks::stats::VendorAtom;
33 using aidl::android::frameworks::stats::VendorAtomValue;
34 using android::sp;
35 using android::chre::HostProtocolHost;
36 using android::chre::IChreMessageHandlers;
37 using android::chre::SocketClient;
38 using android::hardware::google::pixel::PixelAtoms::VendorPhysicalDropDetected;
39
40 // following convention of CHRE code.
41 namespace fbs = ::chre::fbs;
42
43 namespace android {
44 namespace hardware {
45 namespace google {
46 namespace pixel {
47
48 namespace { // anonymous namespace for file-local definitions
49
50 // The following two structs are defined in nanoapps/drop/messaging.h
51 // by the DropDetect nanoapp.
52 struct __attribute__((__packed__)) DropEventPayload {
53 float confidence;
54 float accel_magnitude_peak;
55 int32_t free_fall_duration_ns;
56 };
57
58 struct __attribute__((__packed__)) DropEventPayloadV2 {
59 uint64_t free_fall_duration_ns;
60 float impact_accel_x;
61 float impact_accel_y;
62 float impact_accel_z;
63 };
64
65 // This enum is defined in nanoapps/drop/messaging.h
66 // by the DropDetect nanoapp.
67 enum DropConstants {
68 kDropEnableRequest = 1,
69 kDropEnableNotification = 2,
70 kDropDisableRequest = 3,
71 kDropDisableNotification = 4,
72 kDropEventDetection = 5,
73 kDropEventDetectionV2 = 6,
74 };
75
requestNanoappList(SocketClient * client)76 void requestNanoappList(SocketClient *client) {
77 if (client != nullptr) {
78 flatbuffers::FlatBufferBuilder builder(64);
79 HostProtocolHost::encodeNanoappListRequest(builder);
80
81 if (!client->sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
82 ALOGE("Failed to send NanoappList request");
83 }
84 }
85 }
86
87 } // namespace
88
DropDetect(const uint64_t drop_detect_app_id)89 DropDetect::DropDetect(const uint64_t drop_detect_app_id) : kDropDetectAppId(drop_detect_app_id) {}
90
start(const uint64_t drop_detect_app_id,const char * const chre_socket)91 sp<DropDetect> DropDetect::start(const uint64_t drop_detect_app_id, const char *const chre_socket) {
92 sp<DropDetect> dropDetect = new DropDetect(drop_detect_app_id);
93 if (!dropDetect->connectInBackground(chre_socket, dropDetect)) {
94 ALOGE("Couldn't connect to CHRE socket");
95 return nullptr;
96 }
97 return dropDetect;
98 }
99
onConnected()100 void DropDetect::onConnected() {
101 requestNanoappList(this);
102 }
103
104 /**
105 * Decode unix socket msgs to CHRE messages, and call the appropriate
106 * callback depending on the CHRE message.
107 */
onMessageReceived(const void * data,size_t length)108 void DropDetect::onMessageReceived(const void *data, size_t length) {
109 if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
110 ALOGE("Failed to decode message");
111 }
112 }
113
114 /**
115 * Handle the response of a NanoappList request.
116 * Ensure that the Drop Detect nanoapp is running.
117 */
handleNanoappListResponse(const fbs::NanoappListResponseT & response)118 void DropDetect::handleNanoappListResponse(const fbs::NanoappListResponseT &response) {
119 for (const std::unique_ptr<fbs::NanoappListEntryT> &nanoapp : response.nanoapps) {
120 if (nanoapp->app_id == kDropDetectAppId) {
121 if (!nanoapp->enabled)
122 ALOGE("Drop Detect app not enabled");
123 else
124 ALOGI("Drop Detect enabled");
125 return;
126 }
127 }
128 ALOGE("Drop Detect app not found");
129 }
130
dropEventFromNanoappPayload(const struct DropEventPayload * p)131 static VendorPhysicalDropDetected dropEventFromNanoappPayload(const struct DropEventPayload *p) {
132 ALOGI("Received drop detect message! Confidence %f Peak %f Duration %g",
133 p->confidence, p->accel_magnitude_peak, p->free_fall_duration_ns / 1e9);
134
135 uint8_t confidence = p->confidence * 100;
136 confidence = std::min<int>(confidence, 100);
137 confidence = std::max<int>(0, confidence);
138 int32_t accel_magnitude_peak_1000ths_g = p->accel_magnitude_peak * 1000.0;
139 int32_t free_fall_duration_ms = p->free_fall_duration_ns / 1000000;
140
141 VendorPhysicalDropDetected drop_info;
142 drop_info.set_confidence_pctg(confidence);
143 drop_info.set_accel_peak_thousandths_g(accel_magnitude_peak_1000ths_g);
144 drop_info.set_freefall_time_millis(free_fall_duration_ms);
145 return drop_info;
146 }
147
dropEventFromNanoappPayload(const struct DropEventPayloadV2 * p)148 static VendorPhysicalDropDetected dropEventFromNanoappPayload(const struct DropEventPayloadV2 *p) {
149 ALOGI("Received drop detect message: "
150 "duration %g ms, impact acceleration: x = %f, y = %f, z = %f",
151 p->free_fall_duration_ns / 1e6,
152 p->impact_accel_x,
153 p->impact_accel_y,
154 p->impact_accel_z);
155
156 float impact_magnitude = sqrt(p->impact_accel_x * p->impact_accel_x +
157 p->impact_accel_y * p->impact_accel_y +
158 p->impact_accel_z * p->impact_accel_z);
159 /* Scale impact magnitude as percentage between [50, 100] m/s2. */
160 constexpr float min_confidence_magnitude = 50;
161 constexpr float max_confidence_magnitude = 100;
162 uint8_t confidence_percentage =
163 impact_magnitude < min_confidence_magnitude ? 0 :
164 impact_magnitude > max_confidence_magnitude ? 100 :
165 (impact_magnitude - min_confidence_magnitude) /
166 (max_confidence_magnitude - min_confidence_magnitude) * 100;
167
168 int32_t free_fall_duration_ms = static_cast<int32_t>(p->free_fall_duration_ns / 1000000);
169
170 VendorPhysicalDropDetected drop_info;
171 drop_info.set_confidence_pctg(confidence_percentage);
172 drop_info.set_accel_peak_thousandths_g(static_cast<int32_t>(impact_magnitude * 1000));
173 drop_info.set_freefall_time_millis(free_fall_duration_ms);
174 return drop_info;
175 }
176
reportDropEventToStatsd(const VendorPhysicalDropDetected & drop)177 static void reportDropEventToStatsd(const VendorPhysicalDropDetected &drop) {
178 const std::shared_ptr<IStats> stats_client = getStatsService();
179 if (!stats_client) {
180 ALOGE("Unable to get AIDL Stats service");
181 return;
182 }
183
184 reportPhysicalDropDetected(stats_client, drop);
185 }
186
187 /**
188 * listen for messages from the DropDetect nanoapp and report them to
189 * PixelStats.
190 */
handleNanoappMessage(const fbs::NanoappMessageT & message)191 void DropDetect::handleNanoappMessage(const fbs::NanoappMessageT &message) {
192 if (message.app_id != kDropDetectAppId)
193 return;
194
195 if (message.message_type == kDropEventDetection &&
196 message.message.size() >= sizeof(struct DropEventPayload)) {
197 reportDropEventToStatsd(dropEventFromNanoappPayload(
198 reinterpret_cast<const struct DropEventPayload *>(&message.message[0])));
199 } else if (message.message_type == kDropEventDetectionV2 &&
200 message.message.size() >= sizeof(struct DropEventPayloadV2)) {
201 reportDropEventToStatsd(dropEventFromNanoappPayload(
202 reinterpret_cast<const struct DropEventPayloadV2 *>(&message.message[0])));
203 }
204 }
205
206 } // namespace pixel
207 } // namespace google
208 } // namespace hardware
209 } // namespace android
210