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