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