Merge "trusty: Helper library for metrics" am: e23e85bee5
Original change: https://android-review.googlesource.com/c/platform/system/core/+/1629434 Change-Id: Ie2a265b9ad6b18902a395d12eb2bd9e4d2310b11
This commit is contained in:
commit
1eed4fbf64
5 changed files with 492 additions and 0 deletions
51
trusty/metrics/Android.bp
Normal file
51
trusty/metrics/Android.bp
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright (C) 2021 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.
|
||||||
|
|
||||||
|
package {
|
||||||
|
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_library {
|
||||||
|
name: "libtrusty_metrics",
|
||||||
|
vendor: true,
|
||||||
|
srcs: [
|
||||||
|
"metrics.cpp",
|
||||||
|
],
|
||||||
|
export_include_dirs: [
|
||||||
|
"include",
|
||||||
|
],
|
||||||
|
shared_libs: [
|
||||||
|
"libbase",
|
||||||
|
"liblog",
|
||||||
|
"libtrusty",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_test {
|
||||||
|
name: "libtrusty_metrics_test",
|
||||||
|
vendor: true,
|
||||||
|
srcs: [
|
||||||
|
"metrics_test.cpp",
|
||||||
|
],
|
||||||
|
static_libs: [
|
||||||
|
"libtrusty_metrics",
|
||||||
|
],
|
||||||
|
shared_libs: [
|
||||||
|
"libbase",
|
||||||
|
"libbinder",
|
||||||
|
"liblog",
|
||||||
|
"libtrusty",
|
||||||
|
],
|
||||||
|
require_root: true,
|
||||||
|
}
|
||||||
57
trusty/metrics/include/trusty/metrics/metrics.h
Normal file
57
trusty/metrics/include/trusty/metrics/metrics.h
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <android-base/result.h>
|
||||||
|
#include <android-base/unique_fd.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
namespace trusty {
|
||||||
|
namespace metrics {
|
||||||
|
|
||||||
|
using android::base::Result;
|
||||||
|
using android::base::unique_fd;
|
||||||
|
|
||||||
|
class TrustyMetrics {
|
||||||
|
public:
|
||||||
|
/* Wait for next event with a given timeout. Negative timeout means infinite timeout. */
|
||||||
|
Result<void> WaitForEvent(int timeout_ms = -1);
|
||||||
|
/* Attempt to handle an event from Metrics TA in a non-blocking manner. */
|
||||||
|
Result<void> HandleEvent();
|
||||||
|
/* Expose TIPC channel so that client can integrate it into an event loop with other fds. */
|
||||||
|
int GetRawFd() { return metrics_fd_; };
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TrustyMetrics(std::string tipc_dev) : tipc_dev_(std::move(tipc_dev)), metrics_fd_(-1) {}
|
||||||
|
virtual ~TrustyMetrics(){};
|
||||||
|
|
||||||
|
Result<void> Open();
|
||||||
|
virtual void HandleCrash(const std::string& app_id) = 0;
|
||||||
|
virtual void HandleEventDrop() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string tipc_dev_;
|
||||||
|
unique_fd metrics_fd_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace metrics
|
||||||
|
} // namespace trusty
|
||||||
|
} // namespace android
|
||||||
103
trusty/metrics/include/trusty/metrics/tipc.h
Normal file
103
trusty/metrics/include/trusty/metrics/tipc.h
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOC: Metrics
|
||||||
|
*
|
||||||
|
* Metrics interface provides a way for Android to get Trusty metrics data.
|
||||||
|
*
|
||||||
|
* Currently, only "push" model is supported. Clients are expected to connect to
|
||||||
|
* metrics service, listen for events, e.g. app crash events, and respond to
|
||||||
|
* every event with a &struct metrics_req.
|
||||||
|
*
|
||||||
|
* Communication is driven by metrics service, i.e. requests/responses are all
|
||||||
|
* sent from/to metrics service.
|
||||||
|
*
|
||||||
|
* Note that the type of the event is not known to the client ahead of time.
|
||||||
|
*
|
||||||
|
* In the future, if we need to have Android "pull" metrics data from Trusty,
|
||||||
|
* that can be done by introducing a separate port.
|
||||||
|
*
|
||||||
|
* This interface is shared between Android and Trusty. There is a copy in each
|
||||||
|
* repository. They must be kept in sync.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define METRICS_PORT "com.android.trusty.metrics"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum metrics_cmd - command identifiers for metrics interface
|
||||||
|
* @METRICS_CMD_RESP_BIT: message is a response
|
||||||
|
* @METRICS_CMD_REQ_SHIFT: number of bits used by @METRICS_CMD_RESP_BIT
|
||||||
|
* @METRICS_CMD_REPORT_EVENT_DROP: report gaps in the event stream
|
||||||
|
* @METRICS_CMD_REPORT_CRASH: report an app crash event
|
||||||
|
*/
|
||||||
|
enum metrics_cmd {
|
||||||
|
METRICS_CMD_RESP_BIT = 1,
|
||||||
|
METRICS_CMD_REQ_SHIFT = 1,
|
||||||
|
|
||||||
|
METRICS_CMD_REPORT_EVENT_DROP = (1 << METRICS_CMD_REQ_SHIFT),
|
||||||
|
METRICS_CMD_REPORT_CRASH = (2 << METRICS_CMD_REQ_SHIFT),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum metrics_error - metrics error codes
|
||||||
|
* @METRICS_NO_ERROR: no error
|
||||||
|
* @METRICS_ERR_UNKNOWN_CMD: unknown or not implemented command
|
||||||
|
*/
|
||||||
|
enum metrics_error {
|
||||||
|
METRICS_NO_ERROR = 0,
|
||||||
|
METRICS_ERR_UNKNOWN_CMD = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct metrics_req - common structure for metrics requests
|
||||||
|
* @cmd: command identifier - one of &enum metrics_cmd
|
||||||
|
* @reserved: must be 0
|
||||||
|
*/
|
||||||
|
struct metrics_req {
|
||||||
|
uint32_t cmd;
|
||||||
|
uint32_t reserved;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct metrics_resp - common structure for metrics responses
|
||||||
|
* @cmd: command identifier - %METRICS_CMD_RESP_BIT or'ed with a cmd in
|
||||||
|
* one of &enum metrics_cmd
|
||||||
|
* @status: response status, one of &enum metrics_error
|
||||||
|
*/
|
||||||
|
struct metrics_resp {
|
||||||
|
uint32_t cmd;
|
||||||
|
uint32_t status;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct metrics_report_crash_req - arguments of %METRICS_CMD_REPORT_CRASH
|
||||||
|
* requests
|
||||||
|
* @app_id_len: length of app ID that follows this structure
|
||||||
|
*/
|
||||||
|
struct metrics_report_crash_req {
|
||||||
|
uint32_t app_id_len;
|
||||||
|
} __attribute__((__packed__));
|
||||||
|
|
||||||
|
#define METRICS_MAX_APP_ID_LEN 256
|
||||||
|
|
||||||
|
#define METRICS_MAX_MSG_SIZE \
|
||||||
|
(sizeof(struct metrics_req) + sizeof(struct metrics_report_crash_req) + \
|
||||||
|
METRICS_MAX_APP_ID_LEN)
|
||||||
142
trusty/metrics/metrics.cpp
Normal file
142
trusty/metrics/metrics.cpp
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
139
trusty/metrics/metrics_test.cpp
Normal file
139
trusty/metrics/metrics_test.cpp
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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 <android-base/unique_fd.h>
|
||||||
|
#include <binder/IPCThreadState.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <trusty/metrics/metrics.h>
|
||||||
|
#include <trusty/tipc.h>
|
||||||
|
|
||||||
|
#define TIPC_DEV "/dev/trusty-ipc-dev0"
|
||||||
|
#define CRASHER_PORT "com.android.trusty.metrics.test.crasher"
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
namespace trusty {
|
||||||
|
namespace metrics {
|
||||||
|
|
||||||
|
using android::base::unique_fd;
|
||||||
|
|
||||||
|
static void TriggerCrash() {
|
||||||
|
size_t num_retries = 3;
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_retries; i++) {
|
||||||
|
/* It's possible to time out waiting for crasher TA to restart. */
|
||||||
|
fd = tipc_connect(TIPC_DEV, CRASHER_PORT);
|
||||||
|
if (fd >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_fd crasher(fd);
|
||||||
|
ASSERT_GE(crasher, 0);
|
||||||
|
|
||||||
|
int msg = 0;
|
||||||
|
int rc = write(crasher, &msg, sizeof(msg));
|
||||||
|
ASSERT_EQ(rc, sizeof(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrustyMetricsTest : public TrustyMetrics, public ::testing::Test {
|
||||||
|
public:
|
||||||
|
TrustyMetricsTest() : TrustyMetrics(TIPC_DEV) {}
|
||||||
|
|
||||||
|
virtual void HandleCrash(const std::string& app_id) override { crashed_app_ = app_id; }
|
||||||
|
|
||||||
|
virtual void HandleEventDrop() override { event_drop_count_++; }
|
||||||
|
|
||||||
|
virtual void SetUp() override {
|
||||||
|
auto ret = Open();
|
||||||
|
ASSERT_TRUE(ret.ok()) << ret.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitForAndHandleEvent() {
|
||||||
|
auto ret = WaitForEvent(30000 /* 30 second timeout */);
|
||||||
|
ASSERT_TRUE(ret.ok()) << ret.error();
|
||||||
|
|
||||||
|
ret = HandleEvent();
|
||||||
|
ASSERT_TRUE(ret.ok()) << ret.error();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string crashed_app_;
|
||||||
|
size_t event_drop_count_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(TrustyMetricsTest, Crash) {
|
||||||
|
TriggerCrash();
|
||||||
|
WaitForAndHandleEvent();
|
||||||
|
|
||||||
|
/* Check that correct TA crashed. */
|
||||||
|
ASSERT_EQ(crashed_app_, "36f5b435-5bd3-4526-8b76-200e3a7e79f3:crasher");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TrustyMetricsTest, PollSet) {
|
||||||
|
int binder_fd;
|
||||||
|
int rc = IPCThreadState::self()->setupPolling(&binder_fd);
|
||||||
|
ASSERT_EQ(rc, 0);
|
||||||
|
ASSERT_GE(binder_fd, 0);
|
||||||
|
|
||||||
|
TriggerCrash();
|
||||||
|
|
||||||
|
struct pollfd pfds[] = {
|
||||||
|
{
|
||||||
|
.fd = binder_fd,
|
||||||
|
.events = POLLIN,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.fd = GetRawFd(),
|
||||||
|
.events = POLLIN,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
rc = poll(pfds, 2, 30000 /* 30 second timeout */);
|
||||||
|
/* We expect one event on the metrics fd. */
|
||||||
|
ASSERT_EQ(rc, 1);
|
||||||
|
ASSERT_TRUE(pfds[1].revents & POLLIN);
|
||||||
|
|
||||||
|
auto ret = HandleEvent();
|
||||||
|
ASSERT_TRUE(ret.ok()) << ret.error();
|
||||||
|
|
||||||
|
/* Check that correct TA crashed. */
|
||||||
|
ASSERT_EQ(crashed_app_, "36f5b435-5bd3-4526-8b76-200e3a7e79f3:crasher");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TrustyMetricsTest, EventDrop) {
|
||||||
|
/* We know the size of the internal event queue is less than this. */
|
||||||
|
size_t num_events = 3;
|
||||||
|
|
||||||
|
ASSERT_EQ(event_drop_count_, 0);
|
||||||
|
|
||||||
|
for (auto i = 0; i < num_events; i++) {
|
||||||
|
TriggerCrash();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto i = 0; i < num_events; i++) {
|
||||||
|
WaitForAndHandleEvent();
|
||||||
|
if (event_drop_count_ > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_EQ(event_drop_count_, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace metrics
|
||||||
|
} // namespace trusty
|
||||||
|
} // namespace android
|
||||||
Loading…
Add table
Reference in a new issue