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