/* * Copyright (C) 2021 The Android Open Sourete 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. */ #define LOG_TAG "metrics" #include #include #include #include #include #include #include namespace android { namespace trusty { namespace metrics { using android::base::ErrnoError; using android::base::Error; Result TrustyMetrics::Open() { int fd = tipc_connect(tipc_dev_.c_str(), METRICS_PORT); if (fd < 0) { return ErrnoError() << "failed to connect to Trusty metrics TA"; } int flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { return ErrnoError() << "failed F_GETFL"; } int rc = fcntl(fd, F_SETFL, flags | O_NONBLOCK); if (rc < 0) { return ErrnoError() << "failed F_SETFL"; } metrics_fd_.reset(fd); return {}; } Result TrustyMetrics::WaitForEvent(int timeout_ms) { if (!metrics_fd_.ok()) { return Error() << "connection to Metrics TA has not been initialized yet"; } struct pollfd pfd = { .fd = metrics_fd_, .events = POLLIN, }; int rc = poll(&pfd, 1, timeout_ms); if (rc != 1) { return ErrnoError() << "failed poll()"; } if (!(pfd.revents & POLLIN)) { return ErrnoError() << "channel not ready"; } return {}; } Result TrustyMetrics::HandleEvent() { if (!metrics_fd_.ok()) { return Error() << "connection to Metrics TA has not been initialized yet"; } uint8_t msg[METRICS_MAX_MSG_SIZE]; auto rc = read(metrics_fd_, msg, sizeof(msg)); if (rc < 0) { return ErrnoError() << "failed to read metrics message"; } size_t msg_len = rc; if (msg_len < sizeof(metrics_req)) { return Error() << "message too small: " << rc; } auto req = reinterpret_cast(msg); size_t offset = sizeof(metrics_req); uint32_t status = METRICS_NO_ERROR; switch (req->cmd) { case METRICS_CMD_REPORT_CRASH: { if (msg_len < offset + sizeof(metrics_report_crash_req)) { return Error() << "message too small: " << rc; } auto crash_args = reinterpret_cast(msg + offset); offset += sizeof(metrics_report_crash_req); if (msg_len < offset + crash_args->app_id_len) { return Error() << "message too small: " << rc; } auto app_id_ptr = reinterpret_cast(msg + offset); std::string app_id(app_id_ptr, crash_args->app_id_len); HandleCrash(app_id); break; } case METRICS_CMD_REPORT_EVENT_DROP: HandleEventDrop(); break; default: status = METRICS_ERR_UNKNOWN_CMD; break; } metrics_resp resp = { .cmd = req->cmd | METRICS_CMD_RESP_BIT, .status = status, }; rc = write(metrics_fd_, &resp, sizeof(resp)); if (rc < 0) { return ErrnoError() << "failed to request next metrics event"; } if (rc != (int)sizeof(resp)) { return Error() << "unexpected number of bytes sent event: " << rc; } return {}; } } // namespace metrics } // namespace trusty } // namespace android