xref: /aosp_15_r20/system/nvram/hal/testing_nvram_implementation.cpp (revision 7ba4dab5cc5e3c8f3eb594dcf3b33f99d9214aee)
1*7ba4dab5SXin Li /*
2*7ba4dab5SXin Li  * Copyright (C) 2016 The Android Open Source Project
3*7ba4dab5SXin Li  *
4*7ba4dab5SXin Li  * Licensed under the Apache License, Version 2.0 (the "License");
5*7ba4dab5SXin Li  * you may not use this file except in compliance with the License.
6*7ba4dab5SXin Li  * You may obtain a copy of the License at
7*7ba4dab5SXin Li  *
8*7ba4dab5SXin Li  *      http://www.apache.org/licenses/LICENSE-2.0
9*7ba4dab5SXin Li  *
10*7ba4dab5SXin Li  * Unless required by applicable law or agreed to in writing, software
11*7ba4dab5SXin Li  * distributed under the License is distributed on an "AS IS" BASIS,
12*7ba4dab5SXin Li  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*7ba4dab5SXin Li  * See the License for the specific language governing permissions and
14*7ba4dab5SXin Li  * limitations under the License.
15*7ba4dab5SXin Li  */
16*7ba4dab5SXin Li 
17*7ba4dab5SXin Li #include <errno.h>
18*7ba4dab5SXin Li #include <string.h>
19*7ba4dab5SXin Li #include <sys/socket.h>
20*7ba4dab5SXin Li #include <sys/types.h>
21*7ba4dab5SXin Li #include <unistd.h>
22*7ba4dab5SXin Li 
23*7ba4dab5SXin Li #include <android-base/logging.h>
24*7ba4dab5SXin Li #include <cutils/sockets.h>
25*7ba4dab5SXin Li 
26*7ba4dab5SXin Li #include <nvram/hal/nvram_device_adapter.h>
27*7ba4dab5SXin Li #include <nvram/messages/nvram_messages.h>
28*7ba4dab5SXin Li 
29*7ba4dab5SXin Li namespace {
30*7ba4dab5SXin Li 
31*7ba4dab5SXin Li constexpr char kFakeNvramControlSocketName[] = "nvram";
32*7ba4dab5SXin Li 
33*7ba4dab5SXin Li // This instantiates an |NvramManager| with the storage interface wired up with
34*7ba4dab5SXin Li // an in-memory implementation. This *DOES NOT* meet the persistence and tamper
35*7ba4dab5SXin Li // evidence requirements of the HAL, but is useful for demonstration and running
36*7ba4dab5SXin Li // tests against the |NvramManager| implementation.
37*7ba4dab5SXin Li class TestingNvramImplementation : public nvram::NvramImplementation {
38*7ba4dab5SXin Li  public:
39*7ba4dab5SXin Li   ~TestingNvramImplementation() override;
40*7ba4dab5SXin Li 
41*7ba4dab5SXin Li   void Execute(const nvram::Request& request,
42*7ba4dab5SXin Li                nvram::Response* response) override;
43*7ba4dab5SXin Li 
44*7ba4dab5SXin Li  private:
45*7ba4dab5SXin Li   // Connects the fake NVRAM control socket it it is not open already. Returns
46*7ba4dab5SXin Li   // true if the channel is open, false on errors.
47*7ba4dab5SXin Li   bool Connect();
48*7ba4dab5SXin Li 
49*7ba4dab5SXin Li   // Sends a request to the fake NVRAM daemon. Returns true if successful, false
50*7ba4dab5SXin Li   // on any I/O errors.
51*7ba4dab5SXin Li   bool SendRequest(const nvram::Request& request, nvram::Response* response);
52*7ba4dab5SXin Li 
53*7ba4dab5SXin Li   // A file descriptor of the socket connected to the fake NVRAM daemon.
54*7ba4dab5SXin Li   int nvram_socket_fd_ = -1;
55*7ba4dab5SXin Li 
56*7ba4dab5SXin Li   // The command buffer, used for encoding request and decoding responses.
57*7ba4dab5SXin Li   uint8_t command_buffer_[4096];
58*7ba4dab5SXin Li };
59*7ba4dab5SXin Li 
~TestingNvramImplementation()60*7ba4dab5SXin Li TestingNvramImplementation::~TestingNvramImplementation() {
61*7ba4dab5SXin Li   if (nvram_socket_fd_ != -1) {
62*7ba4dab5SXin Li     // No need to handle EINTR specially here as bionic filters it out.
63*7ba4dab5SXin Li     if (close(nvram_socket_fd_)) {
64*7ba4dab5SXin Li       PLOG(ERROR) << "Failed to close NVRAM command socket";
65*7ba4dab5SXin Li     }
66*7ba4dab5SXin Li     nvram_socket_fd_ = -1;
67*7ba4dab5SXin Li   }
68*7ba4dab5SXin Li }
69*7ba4dab5SXin Li 
Execute(const nvram::Request & request,nvram::Response * response)70*7ba4dab5SXin Li void TestingNvramImplementation::Execute(const nvram::Request& request,
71*7ba4dab5SXin Li                                          nvram::Response* response) {
72*7ba4dab5SXin Li   if (!SendRequest(request, response)) {
73*7ba4dab5SXin Li     response->result = NV_RESULT_INTERNAL_ERROR;
74*7ba4dab5SXin Li   }
75*7ba4dab5SXin Li }
76*7ba4dab5SXin Li 
Connect()77*7ba4dab5SXin Li bool TestingNvramImplementation::Connect() {
78*7ba4dab5SXin Li   if (nvram_socket_fd_ != -1) {
79*7ba4dab5SXin Li     return true;
80*7ba4dab5SXin Li   }
81*7ba4dab5SXin Li 
82*7ba4dab5SXin Li   int rc =
83*7ba4dab5SXin Li       socket_local_client(kFakeNvramControlSocketName,
84*7ba4dab5SXin Li                           ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
85*7ba4dab5SXin Li   if (rc < 0) {
86*7ba4dab5SXin Li     PLOG(ERROR) << "Failed to connect fake NVRAM control socket";
87*7ba4dab5SXin Li     return false;
88*7ba4dab5SXin Li   }
89*7ba4dab5SXin Li 
90*7ba4dab5SXin Li   nvram_socket_fd_ = rc;
91*7ba4dab5SXin Li   return true;
92*7ba4dab5SXin Li }
93*7ba4dab5SXin Li 
SendRequest(const nvram::Request & request,nvram::Response * response)94*7ba4dab5SXin Li bool TestingNvramImplementation::SendRequest(const nvram::Request& request,
95*7ba4dab5SXin Li                                              nvram::Response* response) {
96*7ba4dab5SXin Li   if (!Connect()) {
97*7ba4dab5SXin Li     return false;
98*7ba4dab5SXin Li   }
99*7ba4dab5SXin Li 
100*7ba4dab5SXin Li   size_t request_size = sizeof(command_buffer_);
101*7ba4dab5SXin Li   if (!nvram::Encode(request, command_buffer_, &request_size)) {
102*7ba4dab5SXin Li     LOG(ERROR) << "Failed to encode NVRAM request.";
103*7ba4dab5SXin Li     return false;
104*7ba4dab5SXin Li   }
105*7ba4dab5SXin Li 
106*7ba4dab5SXin Li   ssize_t rc = TEMP_FAILURE_RETRY(
107*7ba4dab5SXin Li       write(nvram_socket_fd_, command_buffer_, request_size));
108*7ba4dab5SXin Li   if (rc < 0) {
109*7ba4dab5SXin Li     PLOG(ERROR) << "Failed to send request on NVRAM control socket";
110*7ba4dab5SXin Li     return false;
111*7ba4dab5SXin Li   }
112*7ba4dab5SXin Li 
113*7ba4dab5SXin Li   rc = TEMP_FAILURE_RETRY(
114*7ba4dab5SXin Li       read(nvram_socket_fd_, command_buffer_, sizeof(command_buffer_)));
115*7ba4dab5SXin Li   if (rc < 0 || static_cast<size_t>(rc) > sizeof(command_buffer_)) {
116*7ba4dab5SXin Li     PLOG(ERROR) << "Failed to read NVRAM response";
117*7ba4dab5SXin Li     return false;
118*7ba4dab5SXin Li   }
119*7ba4dab5SXin Li 
120*7ba4dab5SXin Li   if (!nvram::Decode(command_buffer_, static_cast<size_t>(rc), response)) {
121*7ba4dab5SXin Li     LOG(ERROR) << "Failed to decode NVRAM response.";
122*7ba4dab5SXin Li     return false;
123*7ba4dab5SXin Li   }
124*7ba4dab5SXin Li 
125*7ba4dab5SXin Li   return true;
126*7ba4dab5SXin Li }
127*7ba4dab5SXin Li 
128*7ba4dab5SXin Li }  // namespace
129*7ba4dab5SXin Li 
testing_nvram_open(const hw_module_t * module,const char * device_id,hw_device_t ** device_ptr)130*7ba4dab5SXin Li extern "C" int testing_nvram_open(const hw_module_t* module,
131*7ba4dab5SXin Li                                   const char* device_id,
132*7ba4dab5SXin Li                                   hw_device_t** device_ptr) {
133*7ba4dab5SXin Li   if (strcmp(NVRAM_HARDWARE_DEVICE_ID, device_id) != 0) {
134*7ba4dab5SXin Li     return -EINVAL;
135*7ba4dab5SXin Li   }
136*7ba4dab5SXin Li 
137*7ba4dab5SXin Li   nvram::NvramDeviceAdapter* adapter =
138*7ba4dab5SXin Li       new nvram::NvramDeviceAdapter(module, new TestingNvramImplementation);
139*7ba4dab5SXin Li   *device_ptr = adapter->as_device();
140*7ba4dab5SXin Li   return 0;
141*7ba4dab5SXin Li }
142