1 /*
2 * Copyright (c) 2022, Google, Inc. All rights reserved
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <binder/IBinder.h>
25 #include <lib/binary_search_tree.h>
26 #include <lib/shared/binder_discover/binder_discover.h>
27
28 #if defined(TRUSTY_USERSPACE)
29 #include <binder/RpcSession.h>
30 #include <binder/RpcTransportTipcTrusty.h>
31 #include <lib/tipc/tipc_srv.h>
32 #else
33 #include <kernel/mutex.h>
34 #endif
35
36 struct DiscoveryTreeNode {
37 struct bst_node node;
38 std::string port;
39 android::sp<android::IBinder> binder;
40
41 DiscoveryTreeNode() = delete;
DiscoveryTreeNodeDiscoveryTreeNode42 DiscoveryTreeNode(std::string&& port)
43 : node(BST_NODE_INITIAL_VALUE), port(std::move(port)) {}
DiscoveryTreeNodeDiscoveryTreeNode44 DiscoveryTreeNode(std::string&& port,
45 const android::sp<android::IBinder>& ib)
46 : node(BST_NODE_INITIAL_VALUE), port(std::move(port)), binder(ib) {}
47
compare_by_portDiscoveryTreeNode48 static int compare_by_port(struct bst_node* a, struct bst_node* b) {
49 auto nodea = containerof(a, DiscoveryTreeNode, node);
50 auto nodeb = containerof(b, DiscoveryTreeNode, node);
51 return nodea->port.compare(nodeb->port);
52 }
53 };
54
55 static struct bst_root discovery_tree = BST_ROOT_INITIAL_VALUE;
56
57 #if defined(TRUSTY_USERSPACE)
lock_discovery_tree(void)58 static inline void lock_discovery_tree(void) {}
unlock_discovery_tree(void)59 static inline void unlock_discovery_tree(void) {}
60 #else
61 static mutex_t discovery_tree_lock = MUTEX_INITIAL_VALUE(discovery_tree_lock);
62
lock_discovery_tree(void)63 static inline void lock_discovery_tree(void) {
64 mutex_acquire(&discovery_tree_lock);
65 }
66
unlock_discovery_tree(void)67 static inline void unlock_discovery_tree(void) {
68 mutex_release(&discovery_tree_lock);
69 }
70 #endif
71
binder_discover_get_service(const char * port,android::sp<android::IBinder> & ib)72 int binder_discover_get_service(const char* port,
73 android::sp<android::IBinder>& ib) {
74 // Search the discovery tree to determine whether an in-process binder
75 // exists for this port; if found, return it.
76 DiscoveryTreeNode key{port};
77 lock_discovery_tree();
78 auto node = bst_search(&discovery_tree, &key.node,
79 DiscoveryTreeNode::compare_by_port);
80 if (node != nullptr) {
81 ib = containerof(node, DiscoveryTreeNode, node)->binder;
82 unlock_discovery_tree();
83 return android::OK;
84 }
85 unlock_discovery_tree();
86
87 #if defined(TRUSTY_USERSPACE)
88 android::sp<android::RpcSession> sess = android::RpcSession::make(
89 android::RpcTransportCtxFactoryTipcTrusty::make());
90 android::status_t status = sess->setupPreconnectedClient({}, [=]() {
91 int srv_fd = connect(port, IPC_CONNECT_WAIT_FOR_PORT);
92 return srv_fd >= 0 ? android::binder::unique_fd(srv_fd)
93 : android::binder::unique_fd();
94 });
95 if (status != android::OK) {
96 return status;
97 }
98 ib = sess->getRootObject();
99 #else
100 panic("out-of-process services are currently unsupported in the kernel\n");
101 #endif
102 if (!ib) {
103 return android::BAD_VALUE;
104 }
105 return android::OK;
106 }
107
binder_discover_add_service(const char * port,const android::sp<android::IBinder> & ib)108 int binder_discover_add_service(const char* port,
109 const android::sp<android::IBinder>& ib) {
110 auto node = new (std::nothrow) DiscoveryTreeNode{port, ib};
111 if (node == nullptr) {
112 return android::NO_MEMORY;
113 }
114
115 lock_discovery_tree();
116 auto inserted = bst_insert(&discovery_tree, &node->node,
117 DiscoveryTreeNode::compare_by_port);
118 unlock_discovery_tree();
119
120 if (!inserted) {
121 delete node;
122 return android::ALREADY_EXISTS;
123 }
124
125 return android::OK;
126 }
127
binder_discover_remove_service(const char * port)128 int binder_discover_remove_service(const char* port) {
129 DiscoveryTreeNode key{port};
130 lock_discovery_tree();
131 auto node = bst_search(&discovery_tree, &key.node,
132 DiscoveryTreeNode::compare_by_port);
133 if (node != nullptr) {
134 bst_delete(&discovery_tree, node);
135 }
136 unlock_discovery_tree();
137
138 if (node == nullptr) {
139 return android::NAME_NOT_FOUND;
140 }
141
142 // Destruct and free the underlying DiscoveryTreeNode
143 auto full_node = containerof(node, DiscoveryTreeNode, node);
144 delete full_node;
145
146 return android::OK;
147 }
148