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