| /* |
| * 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 <android-base/logging.h> |
| #include <fcntl.h> |
| #include <poll.h> |
| #include <trusty/metrics/metrics.h> |
| #include <trusty/metrics/tipc.h> |
| #include <trusty/tipc.h> |
| #include <unistd.h> |
| |
| namespace android { |
| namespace trusty { |
| namespace metrics { |
| |
| using android::base::ErrnoError; |
| using android::base::Error; |
| |
| Result<void> 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<void> 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<void> 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<metrics_req*>(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<metrics_report_crash_req*>(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<char*>(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 |