blob: cfac32495120f179e3c2333a6e489fae33723983 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <pixelstats/DropDetect.h>
#include <chre/util/nanoapp/app_id.h>
#include <chre_host/host_protocol_host.h>
#include <chre_host/socket_client.h>
#include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
#include <pixelstats/StatsHelper.h>
#define LOG_TAG "pixelstats-vendor"
#include <log/log.h>
#include <inttypes.h>
#include <math.h>
using aidl::android::frameworks::stats::IStats;
using aidl::android::frameworks::stats::VendorAtom;
using aidl::android::frameworks::stats::VendorAtomValue;
using android::sp;
using android::chre::HostProtocolHost;
using android::chre::IChreMessageHandlers;
using android::chre::SocketClient;
using android::hardware::google::pixel::PixelAtoms::VendorPhysicalDropDetected;
// following convention of CHRE code.
namespace fbs = ::chre::fbs;
namespace android {
namespace hardware {
namespace google {
namespace pixel {
namespace { // anonymous namespace for file-local definitions
// The following two structs are defined in nanoapps/drop/messaging.h
// by the DropDetect nanoapp.
struct __attribute__((__packed__)) DropEventPayload {
float confidence;
float accel_magnitude_peak;
int32_t free_fall_duration_ns;
};
struct __attribute__((__packed__)) DropEventPayloadV2 {
uint64_t free_fall_duration_ns;
float impact_accel_x;
float impact_accel_y;
float impact_accel_z;
};
// This enum is defined in nanoapps/drop/messaging.h
// by the DropDetect nanoapp.
enum DropConstants {
kDropEnableRequest = 1,
kDropEnableNotification = 2,
kDropDisableRequest = 3,
kDropDisableNotification = 4,
kDropEventDetection = 5,
kDropEventDetectionV2 = 6,
};
void requestNanoappList(SocketClient *client) {
if (client != nullptr) {
flatbuffers::FlatBufferBuilder builder(64);
HostProtocolHost::encodeNanoappListRequest(builder);
if (!client->sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
ALOGE("Failed to send NanoappList request");
}
}
}
} // namespace
DropDetect::DropDetect(const uint64_t drop_detect_app_id) : kDropDetectAppId(drop_detect_app_id) {}
sp<DropDetect> DropDetect::start(const uint64_t drop_detect_app_id, const char *const chre_socket) {
sp<DropDetect> dropDetect = new DropDetect(drop_detect_app_id);
if (!dropDetect->connectInBackground(chre_socket, dropDetect)) {
ALOGE("Couldn't connect to CHRE socket");
return nullptr;
}
return dropDetect;
}
void DropDetect::onConnected() {
requestNanoappList(this);
}
/**
* Decode unix socket msgs to CHRE messages, and call the appropriate
* callback depending on the CHRE message.
*/
void DropDetect::onMessageReceived(const void *data, size_t length) {
if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
ALOGE("Failed to decode message");
}
}
/**
* Handle the response of a NanoappList request.
* Ensure that the Drop Detect nanoapp is running.
*/
void DropDetect::handleNanoappListResponse(const fbs::NanoappListResponseT &response) {
for (const std::unique_ptr<fbs::NanoappListEntryT> &nanoapp : response.nanoapps) {
if (nanoapp->app_id == kDropDetectAppId) {
if (!nanoapp->enabled)
ALOGE("Drop Detect app not enabled");
else
ALOGI("Drop Detect enabled");
return;
}
}
ALOGE("Drop Detect app not found");
}
static VendorPhysicalDropDetected dropEventFromNanoappPayload(const struct DropEventPayload *p) {
ALOGI("Received drop detect message! Confidence %f Peak %f Duration %g",
p->confidence, p->accel_magnitude_peak, p->free_fall_duration_ns / 1e9);
uint8_t confidence = p->confidence * 100;
confidence = std::min<int>(confidence, 100);
confidence = std::max<int>(0, confidence);
int32_t accel_magnitude_peak_1000ths_g = p->accel_magnitude_peak * 1000.0;
int32_t free_fall_duration_ms = p->free_fall_duration_ns / 1000000;
VendorPhysicalDropDetected drop_info;
drop_info.set_confidence_pctg(confidence);
drop_info.set_accel_peak_thousandths_g(accel_magnitude_peak_1000ths_g);
drop_info.set_freefall_time_millis(free_fall_duration_ms);
return drop_info;
}
static VendorPhysicalDropDetected dropEventFromNanoappPayload(const struct DropEventPayloadV2 *p) {
ALOGI("Received drop detect message: "
"duration %g ms, impact acceleration: x = %f, y = %f, z = %f",
p->free_fall_duration_ns / 1e6,
p->impact_accel_x,
p->impact_accel_y,
p->impact_accel_z);
float impact_magnitude = sqrt(p->impact_accel_x * p->impact_accel_x +
p->impact_accel_y * p->impact_accel_y +
p->impact_accel_z * p->impact_accel_z);
/* Scale impact magnitude as percentage between [50, 100] m/s2. */
constexpr float min_confidence_magnitude = 50;
constexpr float max_confidence_magnitude = 100;
uint8_t confidence_percentage =
impact_magnitude < min_confidence_magnitude ? 0 :
impact_magnitude > max_confidence_magnitude ? 100 :
(impact_magnitude - min_confidence_magnitude) /
(max_confidence_magnitude - min_confidence_magnitude) * 100;
int32_t free_fall_duration_ms = static_cast<int32_t>(p->free_fall_duration_ns / 1000000);
VendorPhysicalDropDetected drop_info;
drop_info.set_confidence_pctg(confidence_percentage);
drop_info.set_accel_peak_thousandths_g(static_cast<int32_t>(impact_magnitude * 1000));
drop_info.set_freefall_time_millis(free_fall_duration_ms);
return drop_info;
}
static void reportDropEventToStatsd(const VendorPhysicalDropDetected &drop) {
const std::shared_ptr<IStats> stats_client = getStatsService();
if (!stats_client) {
ALOGE("Unable to get AIDL Stats service");
return;
}
reportPhysicalDropDetected(stats_client, drop);
}
/**
* listen for messages from the DropDetect nanoapp and report them to
* PixelStats.
*/
void DropDetect::handleNanoappMessage(const fbs::NanoappMessageT &message) {
if (message.app_id != kDropDetectAppId)
return;
if (message.message_type == kDropEventDetection &&
message.message.size() >= sizeof(struct DropEventPayload)) {
reportDropEventToStatsd(dropEventFromNanoappPayload(
reinterpret_cast<const struct DropEventPayload *>(&message.message[0])));
} else if (message.message_type == kDropEventDetectionV2 &&
message.message.size() >= sizeof(struct DropEventPayloadV2)) {
reportDropEventToStatsd(dropEventFromNanoappPayload(
reinterpret_cast<const struct DropEventPayloadV2 *>(&message.message[0])));
}
}
} // namespace pixel
} // namespace google
} // namespace hardware
} // namespace android