• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2018 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  #include <lib/unittest/unittest.h>
18  #include <lib/coverage/common/cov_shm.h>
19  #include <interface/line-coverage/aggregator.h>
20  #include <lib/line-coverage/shm.h>
21  #include <lib/coverage/common/ipc.h>
22  #include <lib/tipc/tipc.h>
23  #include <lib/tipc/tipc_srv.h>
24  #include <lk/macros.h>
25  #include <stdarg.h>
26  #include <stddef.h>
27  #include <stdio.h>
28  #include <stdlib.h>
29  #include <string.h>
30  #include <trusty/time.h>
31  #include <trusty_ipc.h>
32  #include <uapi/err.h>
33  
34  #define LOG_TAG "unittest"
35  
36  #include <lk/trace.h>
37  
38  #define MAX_PORT_BUF_SIZE 4096 /* max size of per port buffer    */
39  
40  /*
41   * We can't use the normal TLOG functions because they send data through the
42   * channel managed by this code.
43   */
44  
45  #define TLOGI(fmt, ...)                                                    \
46      do {                                                                   \
47          fprintf(stderr, "%s: %d: " fmt, LOG_TAG, __LINE__, ##__VA_ARGS__); \
48      } while (0)
49  
50  static handle_t ipc_printf_handle = INVALID_IPC_HANDLE;
51  
send_msg_wait(handle_t handle,struct ipc_msg * msg)52  static int send_msg_wait(handle_t handle, struct ipc_msg* msg) {
53      int ret;
54      struct uevent ev;
55  
56      ret = send_msg(handle, msg);
57      if (ret != ERR_NOT_ENOUGH_BUFFER) {
58          return ret;
59      }
60  
61      ret = wait(handle, &ev, INFINITE_TIME);
62      if (ret < 0) {
63          return ret;
64      }
65  
66      if (ev.event & IPC_HANDLE_POLL_SEND_UNBLOCKED) {
67          return send_msg(handle, msg);
68      }
69  
70      if (ev.event & IPC_HANDLE_POLL_MSG) {
71          return ERR_BUSY;
72      }
73  
74      if (ev.event & IPC_HANDLE_POLL_HUP) {
75          return ERR_CHANNEL_CLOSED;
76      }
77  
78      return ret;
79  }
80  
get_current_time_ns(void)81  uint64_t get_current_time_ns(void) {
82      int64_t res;
83      trusty_gettime(0, &res);
84      return (uint64_t)res;
85  }
86  
87  enum test_message_header {
88      TEST_PASSED = 0,
89      TEST_FAILED = 1,
90      TEST_MESSAGE = 2,
91      TEST_MESSAGE_HEADER_COUNT = 3,
92  };
93  
_vtlog(const char * fmt,va_list args)94  int _vtlog(const char* fmt, va_list args) {
95      char buf[256];
96      struct iovec tx_iov = {buf, 1};
97      ipc_msg_t tx_msg = {1, &tx_iov, 0, NULL};
98      va_list ap;
99      int ret;
100      int slen;
101  
102      /* Print to stderr as normal */
103      va_copy(ap, args);
104      ret = vfprintf(stderr, fmt, ap);
105      va_end(ap);
106      if (ret < 0) {
107          return ret;
108      }
109  
110      /* Send over IPC */
111      if (ipc_printf_handle == INVALID_IPC_HANDLE) {
112          return 0;
113      }
114  
115      va_copy(ap, args);
116      /* use filtered version for consistency with stderr logging */
117      ret = vsnprintf_filtered(buf + 1, sizeof(buf) - 1, fmt, ap);
118      va_end(ap);
119  
120      if (ret < 0) {
121          return ret;
122      }
123      slen = MIN(ret, (int)sizeof(buf) - 1 - 1);
124  
125      buf[0] = TEST_MESSAGE;
126      tx_iov.iov_len = 1 + slen;
127      ret = send_msg_wait(ipc_printf_handle, &tx_msg);
128      if (ret < 0) {
129          return ret;
130      }
131  
132      return slen;
133  }
134  
135  /*
136   *  Application entry point
137   */
unittest_main(struct unittest ** tests,size_t test_count)138  int unittest_main(struct unittest** tests, size_t test_count) {
139      int ret;
140      handle_t hset;
141      uevent_t evt = {
142              .event = ~0U,
143      };
144      struct unittest* test;
145      uuid_t unused_uuid;
146  
147      ret = handle_set_create();
148      if (ret < 0) {
149          TLOGI("failed to create handle set: %d\n", ret);
150          return ret;
151      }
152      hset = ret;
153  
154      /* create control port and just wait on it */
155      for (; test_count; test_count--) {
156          test = *tests++;
157          ret = port_create(
158                  test->port_name, 1, MAX_PORT_BUF_SIZE,
159                  IPC_PORT_ALLOW_NS_CONNECT | IPC_PORT_ALLOW_TA_CONNECT);
160          if (ret < 0) {
161              TLOGI("failed to create port %s: %d\n", test->port_name, ret);
162              return ret;
163          }
164          test->_port_handle = (handle_t)ret;
165          evt.handle = test->_port_handle;
166          evt.cookie = test;
167          ret = handle_set_ctrl(hset, HSET_ADD, &evt);
168          if (ret < 0) {
169              TLOGI("failed to add %s to handle set: %d\n", test->port_name, ret);
170              return ret;
171          }
172      }
173  
174      setup_mailbox(&((struct tipc_port){ .name = test->port_name }), 1);
175  
176      /* and just wait forever for now */
177      for (;;) {
178          ret = wait(hset, &evt, INFINITE_TIME);
179          test = evt.cookie;
180          TLOGI("got event (ret=%d): ev=%x handle=%d port=%s\n", ret, evt.event,
181                evt.handle, test->port_name);
182          if (ret < 0)
183              break;
184          if (evt.event & IPC_HANDLE_POLL_READY) {
185              /* get connection request */
186              setup_shm();
187              ret = accept(evt.handle, &unused_uuid);
188              TLOGI("accept returned %d\n", ret);
189              if (ret >= 0) {
190                  char tx_buffer[1];
191                  struct iovec tx_iov = {
192                          tx_buffer,
193                          sizeof(tx_buffer),
194                  };
195                  ipc_msg_t tx_msg = {1, &tx_iov, 0, NULL};
196  
197                  /* then run unittest test */
198                  ipc_printf_handle = ret;
199                  tx_buffer[0] = test->run_test(test) ? TEST_PASSED : TEST_FAILED;
200                  ipc_printf_handle = INVALID_IPC_HANDLE;
201  
202                  send_msg_wait(ret, &tx_msg);
203  
204                  /* and close it */
205                  close(ret);
206  
207                  dump_shm();
208              }
209          }
210      }
211  
212      return ret;
213  }
214