1 /* 2 * Copyright (C) 2019 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 "Utils.h" 18 19 #ifdef __BIONIC__ 20 #include <cutils/properties.h> 21 #endif // __BIONIC__ 22 23 #include <getopt.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <sys/select.h> 27 #include <unistd.h> 28 #include <array> 29 #include <climits> 30 #include <iostream> 31 #include <sstream> 32 33 using std::cerr; 34 using std::endl; 35 36 namespace android { 37 namespace hardware { 38 namespace automotive { 39 namespace vehicle { 40 namespace V2_0 { 41 namespace impl { 42 43 #ifdef __BIONIC__ 44 std::string VirtualizedVhalServerInfo::getServerUri() const { 45 return vsock.str(); 46 } 47 #else 48 std::string VirtualizedVhalServerInfo::getServerUri() const { 49 std::stringstream ss; 50 51 ss << "vsock:" << vsock.cid << ":" << vsock.port; 52 return ss.str(); 53 } 54 #endif 55 56 bool WaitForReadWithTimeout(int fd, struct timeval&& timeout) { 57 fd_set read_fd_set; 58 FD_ZERO(&read_fd_set); 59 FD_SET(fd, &read_fd_set); 60 auto ready = select(FD_SETSIZE, &read_fd_set, nullptr, nullptr, &timeout); 61 62 if (ready < 0) { 63 cerr << __func__ << ": fd: " << fd << ", errno: " << errno << ", " << strerror(errno) 64 << endl; 65 return false; 66 } 67 return ready > 0; 68 } 69 70 static std::optional<unsigned> parseUnsignedIntFromString(const char* optarg, const char* name) { 71 auto v = strtoul(optarg, nullptr, 0); 72 if (((v == ULONG_MAX) && (errno == ERANGE)) || (v > UINT_MAX)) { 73 cerr << name << " value is out of range: " << optarg << endl; 74 } else if (v != 0) { 75 return v; 76 } else { 77 cerr << name << " value is invalid or missing: " << optarg << endl; 78 } 79 80 return std::nullopt; 81 } 82 83 std::optional<VirtualizedVhalServerInfo> VirtualizedVhalServerInfo::fromCommandLine( 84 int argc, char* argv[], std::string* error) { 85 // TODO(egranata): move command-line parsing into vsockinfo 86 std::optional<unsigned int> cid; 87 std::optional<unsigned int> port; 88 std::optional<std::string> powerStateMarkerFilePath; 89 std::optional<std::string> powerStateSocketPath; 90 91 // unique values to identify the options 92 constexpr int OPT_VHAL_SERVER_CID = 1001; 93 constexpr int OPT_VHAL_SERVER_PORT_NUMBER = 1002; 94 constexpr int OPT_VHAL_SERVER_POWER_STATE_FILE = 1003; 95 constexpr int OPT_VHAL_SERVER_POWER_STATE_SOCKET = 1004; 96 97 struct option longOptions[] = { 98 {"server_cid", 1, 0, OPT_VHAL_SERVER_CID}, 99 {"server_port", 1, 0, OPT_VHAL_SERVER_PORT_NUMBER}, 100 {"power_state_file", 1, 0, OPT_VHAL_SERVER_POWER_STATE_FILE}, 101 {"power_state_socket", 1, 0, OPT_VHAL_SERVER_POWER_STATE_SOCKET}, 102 {}, 103 }; 104 105 int optValue; 106 while ((optValue = getopt_long_only(argc, argv, ":", longOptions, 0)) != -1) { 107 switch (optValue) { 108 case OPT_VHAL_SERVER_CID: 109 cid = parseUnsignedIntFromString(optarg, "cid"); 110 break; 111 case OPT_VHAL_SERVER_PORT_NUMBER: 112 port = parseUnsignedIntFromString(optarg, "port"); 113 break; 114 case OPT_VHAL_SERVER_POWER_STATE_FILE: 115 powerStateMarkerFilePath = std::string(optarg); 116 break; 117 case OPT_VHAL_SERVER_POWER_STATE_SOCKET: 118 powerStateSocketPath = std::string(optarg); 119 break; 120 default: 121 // ignore other options 122 break; 123 } 124 } 125 126 if (!cid.has_value() && error) { 127 *error += "Missing server CID. "; 128 } 129 if (!port.has_value() && error) { 130 *error += "Missing server port number. "; 131 } 132 if (!powerStateMarkerFilePath.has_value() && error) { 133 *error += "Missing power state marker file path. "; 134 } 135 if (!powerStateSocketPath.has_value() && error) { 136 *error += "Missing power state socket path. "; 137 } 138 139 if (cid && port && powerStateMarkerFilePath && powerStateSocketPath) { 140 return VirtualizedVhalServerInfo{ 141 {*cid, *port}, *powerStateMarkerFilePath, *powerStateSocketPath}; 142 } 143 return std::nullopt; 144 } 145 146 #ifdef __BIONIC__ 147 std::optional<VirtualizedVhalServerInfo> VirtualizedVhalServerInfo::fromRoPropertyStore() { 148 auto vsock = android::hardware::automotive::utils::VsockConnectionInfo::fromRoPropertyStore( 149 { 150 "ro.boot.vendor.vehiclehal.server.cid", 151 "ro.vendor.vehiclehal.server.cid", 152 }, 153 { 154 "ro.boot.vendor.vehiclehal.server.port", 155 "ro.vendor.vehiclehal.server.port", 156 }); 157 158 if (vsock) { 159 return VirtualizedVhalServerInfo{*vsock, "", ""}; 160 } 161 return std::nullopt; 162 } 163 #endif // __BIONIC__ 164 165 } // namespace impl 166 } // namespace V2_0 167 } // namespace vehicle 168 } // namespace automotive 169 } // namespace hardware 170 } // namespace android 171