xref: /aosp_15_r20/system/server_configurable_flags/aconfigd/aconfigd_socket_test.cpp (revision 207333786ba243bc7d4d69ef6b05487aa7071806)
1 /*
2  * Copyright (C) 2024 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 <sys/socket.h>
18 #include <sys/un.h>
19 
20 #include <gtest/gtest.h>
21 #include <cutils/sockets.h>
22 #include <android-base/file.h>
23 #include <android-base/result.h>
24 #include <android-base/logging.h>
25 #include <android-base/unique_fd.h>
26 
27 #include <aconfigd.pb.h>
28 #include "com_android_aconfig_new_storage.h"
29 
30 using namespace android::base;
31 
32 namespace android {
33 namespace aconfigd {
34 
35 class AconfigdSocketTest : public ::testing::Test {
36  protected:
connect_aconfigd_socket()37   Result<unique_fd> connect_aconfigd_socket() {
38     auto sock_fd = unique_fd(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0));
39     if (sock_fd == -1) {
40       return ErrnoError() << "failed create socket";
41     }
42 
43     auto addr = sockaddr_un();
44     addr.sun_family = AF_UNIX;
45     auto path = std::string("/dev/socket/aconfigd");
46     strlcpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path));
47 
48     bool success = false;
49     for (int retry = 0; retry < 5; retry++) {
50       if (connect(sock_fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == 0) {
51         success = true;
52         break;
53       }
54       sleep(1);
55     }
56 
57     if (!success) {
58       return ErrnoError() << "failed to connect to aconfigd socket";
59     }
60 
61     return sock_fd;
62   }
63 
64   // send a message to aconfigd socket, and capture return message
send_message(const StorageRequestMessages & messages)65   Result<StorageReturnMessages> send_message(const StorageRequestMessages& messages) {
66     auto sock_fd = connect_aconfigd_socket();
67     if (!sock_fd.ok()) {
68       return Error() << sock_fd.error();
69     }
70 
71     auto message_string = std::string();
72     if (!messages.SerializeToString(&message_string)) {
73       return Error() << "failed to serialize pb to string";
74     }
75 
76     unsigned char bytes[4];
77     uint32_t msg_size = message_string.size();
78     bytes[0] = (msg_size >> 24) & 0xFF;
79     bytes[1] = (msg_size >> 16) & 0xFF;
80     bytes[2] = (msg_size >> 8) & 0xFF;
81     bytes[3] = (msg_size >> 0) & 0xFF;
82 
83     auto num_bytes = TEMP_FAILURE_RETRY(send(*sock_fd, bytes, 4, 0));
84     if (num_bytes != 4) {
85       return ErrnoError() << "send() failed for msg size";
86     }
87 
88     num_bytes = TEMP_FAILURE_RETRY(
89         send(*sock_fd, message_string.c_str(), message_string.size(), 0));
90     if (num_bytes != static_cast<long>(message_string.size())) {
91       return ErrnoError() << "send() failed for msg";
92     }
93 
94     num_bytes = TEMP_FAILURE_RETRY(recv(*sock_fd, bytes, 4, 0));
95     if (num_bytes != 4) {
96       return ErrnoError() << "recv() failed for return msg size";
97     }
98 
99     uint32_t payload_size =
100         uint32_t(bytes[0]<<24 | bytes[1]<<16 | bytes[2]<<8 | bytes[3]);
101     char buffer[payload_size];
102     int payload_bytes_received = 0;
103     while (payload_bytes_received < payload_size) {
104       auto chunk_bytes = TEMP_FAILURE_RETRY(
105           recv(*sock_fd, buffer + payload_bytes_received,
106                payload_size - payload_bytes_received, 0));
107       if (chunk_bytes <= 0) {
108         return ErrnoError() << "recv() failed for return msg";
109       }
110       payload_bytes_received += chunk_bytes;
111     }
112 
113     auto return_messages = StorageReturnMessages{};
114     if (!return_messages.ParseFromString(std::string(buffer, payload_size))) {
115       return Error() << "failed to parse string into proto";
116     }
117 
118     if (return_messages.msgs_size() != messages.msgs_size()) {
119       return Error() << "Send " << messages.msgs_size() << " request messages, get "
120                      << return_messages.msgs_size() << " return messages";
121     }
122 
123     return return_messages;
124   }
125 
add_new_storage_message(StorageRequestMessages & messages)126   void add_new_storage_message(StorageRequestMessages& messages) {
127     auto* message = messages.add_msgs();
128     auto* msg = message->mutable_new_storage_message();
129     auto test_dir = base::GetExecutableDirectory();
130     msg->set_container("mockup");
131     msg->set_package_map(test_dir + "/tests/data/v1/package.map");
132     msg->set_flag_map(test_dir + "/tests/data/v1/flag.map");
133     msg->set_flag_value(test_dir + "/tests/data/v1/flag.val");
134   }
135 
add_flag_query_message(StorageRequestMessages & messages,const std::string & package,const std::string & flag)136   void add_flag_query_message(StorageRequestMessages& messages,
137                               const std::string& package,
138                               const std::string& flag) {
139     auto* message = messages.add_msgs();
140     auto* msg = message->mutable_flag_query_message();
141     msg->set_package_name(package);
142     msg->set_flag_name(flag);
143   }
144 
add_list_storage_message(StorageRequestMessages & messages)145   void add_list_storage_message(StorageRequestMessages& messages) {
146     auto* message = messages.add_msgs();
147     auto* msg = message->mutable_list_storage_message();
148     msg->set_all(true);
149   }
150 
verify_new_storage_return_message(const StorageReturnMessage & msg)151   void verify_new_storage_return_message(const StorageReturnMessage& msg) {
152     ASSERT_TRUE(msg.has_new_storage_message()) << msg.error_message();
153     auto message = msg.new_storage_message();
154     ASSERT_TRUE(message.storage_updated());
155   }
156 
verify_list_storage_return_message(const StorageReturnMessage & msg)157   void verify_list_storage_return_message(const StorageReturnMessage& msg) {
158     ASSERT_TRUE(msg.has_list_storage_message()) << msg.error_message();
159   }
160 
verify_error_message(const StorageReturnMessage & msg,const std::string & errmsg)161   void verify_error_message(const StorageReturnMessage& msg,
162                             const std::string& errmsg) {
163     ASSERT_TRUE(msg.has_error_message());
164     ASSERT_TRUE(msg.error_message().find(errmsg) != std::string::npos)
165         << msg.error_message();
166   }
167 }; // class AconfigdSocketTest
168 
169 // single request test
TEST_F(AconfigdSocketTest,single_request)170 TEST_F(AconfigdSocketTest, single_request) {
171   if (!com::android::aconfig_new_storage::enable_aconfig_storage_daemon()) {
172     return;
173   }
174   auto request_msgs = StorageRequestMessages();
175   add_flag_query_message(request_msgs, "unknown_package", "unknown_flag");
176   auto return_msgs = send_message(request_msgs);
177   ASSERT_TRUE(return_msgs.ok()) << return_msgs.error();
178   verify_error_message(return_msgs->msgs(0), "container not found");
179 }
180 
181 // multiple request test
TEST_F(AconfigdSocketTest,multiple_requests)182 TEST_F(AconfigdSocketTest, multiple_requests) {
183   if (!com::android::aconfig_new_storage::enable_aconfig_storage_daemon()) {
184     return;
185   }
186   auto request_msgs = StorageRequestMessages();
187   size_t num_msgs = 10;
188   for (size_t i=0; i<num_msgs; ++i) {
189     add_flag_query_message(request_msgs, "unknown_package", "unknown_flag");
190   }
191   auto return_msgs = send_message(request_msgs);
192   ASSERT_TRUE(return_msgs.ok()) << return_msgs.error();
193   for (size_t i=0; i<num_msgs; ++i) {
194     verify_error_message(return_msgs->msgs(i), "container not found");
195   }
196 }
197 
198 // add a mockup container
TEST_F(AconfigdSocketTest,add_new_storage)199 TEST_F(AconfigdSocketTest, add_new_storage) {
200   return;
201   auto request_msgs = StorageRequestMessages();
202   add_new_storage_message(request_msgs);
203   auto return_msgs = send_message(request_msgs);
204   ASSERT_TRUE(return_msgs.ok()) << return_msgs.error();
205   verify_new_storage_return_message(return_msgs->msgs(0));
206 }
207 
TEST_F(AconfigdSocketTest,storage_list_package)208 TEST_F(AconfigdSocketTest, storage_list_package) {
209   if (!com::android::aconfig_new_storage::enable_aconfig_storage_daemon()) {
210     return;
211   }
212   auto request_msgs = StorageRequestMessages();
213   add_list_storage_message(request_msgs);
214   auto return_msgs = send_message(request_msgs);
215   ASSERT_TRUE(return_msgs.ok()) << return_msgs.error();
216   verify_list_storage_return_message(return_msgs->msgs(0));
217 }
218 
219 } // namespace aconfigd
220 } // namespace android
221