1 /*
2 * Copyright (C) 2021 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
17 #define TLOG_TAG "metrics-consumer"
18 #include "consumer.h"
19
20 #include <interface/metrics/consumer.h>
21 #include <lib/tipc/tipc.h>
22 #include <lib/tipc/tipc_srv.h>
23 #include <metrics_consts.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <trusty_log.h>
27 #include <uapi/err.h>
28
29 /*
30 Current use cases:
31 1) Metrics daemon
32 2) Trusty kernel metrics reporter
33 3) Storage metrics
34 4) Android metrics test
35 */
36 #define MAX_METRICS_TA_CONNECTIONS 4
37
38 static const struct uuid zero_uuid = UUID_INITIAL_VALUE(zero_uuid);
39
is_zero_uuid(const struct uuid * peer)40 static bool is_zero_uuid(const struct uuid* peer) {
41 return equal_uuid(peer, &zero_uuid);
42 }
43
on_connect(const struct tipc_port * port,handle_t chan,const struct uuid * peer,void ** ctx_p)44 static int on_connect(const struct tipc_port* port,
45 handle_t chan,
46 const struct uuid* peer,
47 void** ctx_p) {
48
49 struct srv_state* state = get_srv_state(port);
50 if(is_zero_uuid(peer))
51 {
52 TLOGD("Updating metrics daemon handle :%d\n", chan);
53 if(state->ns_handle != INVALID_IPC_HANDLE) {
54 close(state->ns_handle);
55 }
56 state->ns_handle = chan;
57 }
58
59 return NO_ERROR;
60 }
61
on_message(const struct tipc_port * port,handle_t chan,void * ctx)62 static int on_message(const struct tipc_port* port, handle_t chan, void* ctx) {
63 int rc;
64 struct metrics_req req;
65 uint8_t msg[METRICS_MAX_MSG_SIZE];
66
67 memset(msg, 0, sizeof(msg));
68 int msg_size = tipc_recv1(chan, sizeof(req), msg, sizeof(msg));
69 if (msg_size < 0) {
70 TLOGE("failed (%d) to receive metrics event\n", msg_size);
71 return msg_size;
72 }
73
74 // Check if NS metricsd connected, if so forward it there.
75 struct srv_state* state = get_srv_state(port);
76 if(is_ns_connected(state)) {
77 rc = tipc_send1(state->ns_handle, msg, msg_size);
78 if (rc < 0) {
79 TLOGE("failed (%d) to send metrics event tp NS metricsd\n", rc);
80 return rc;
81 }
82 }
83 else {
84 TLOGD("NS metrics daemon not connected\n");
85 }
86
87 uint32_t cmd;
88 cmd = ((struct metrics_req*)msg)->cmd;
89 struct metrics_resp resp = {
90 .cmd = (cmd | METRICS_CMD_RESP_BIT)
91 };
92
93 rc = tipc_send1(chan, &resp, sizeof(resp));
94 if (rc < 0) {
95 TLOGE("failed (%d) to send metrics event response\n", rc);
96 return rc;
97 }
98
99 if ((size_t)rc != sizeof(resp)) {
100 TLOGE("unexpected number of bytes sent: %d\n", rc);
101 return ERR_BAD_LEN;
102 }
103
104 return NO_ERROR;
105 }
106
add_metrics_consumer_service(struct tipc_hset * hset,struct srv_state * state)107 int add_metrics_consumer_service(struct tipc_hset* hset, struct srv_state* state) {
108 static struct tipc_port_acl port_acl = {
109 .flags = IPC_PORT_ALLOW_TA_CONNECT | IPC_PORT_ALLOW_NS_CONNECT,
110 };
111 static struct tipc_port port = {
112 .name = METRICS_CONSUMER_PORT,
113 .msg_max_size = METRICS_MAX_MSG_SIZE,
114 .msg_queue_len = 1,
115 .acl = &port_acl,
116 };
117 static struct tipc_srv_ops ops = {
118 .on_message = on_message,
119 .on_connect = on_connect,
120 };
121 set_srv_state(&port, state);
122
123 return tipc_add_service(hset, &port, 1, MAX_METRICS_TA_CONNECTIONS, &ops);
124 }