1 /* 2 * Copyright (C) 2017 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 #define LOG_TAG "lshal" 18 #include <android-base/logging.h> 19 20 #include "Lshal.h" 21 22 #include <set> 23 #include <string> 24 25 #include <hidl/ServiceManagement.h> 26 #include <hidl/HidlTransportUtils.h> 27 28 #include "DebugCommand.h" 29 #include "ListCommand.h" 30 #include "PipeRelay.h" 31 32 namespace android { 33 namespace lshal { 34 35 using ::android::hidl::manager::V1_0::IServiceManager; 36 37 Lshal::Lshal() 38 : Lshal(std::cout, std::cerr, ::android::hardware::defaultServiceManager(), 39 ::android::hardware::getPassthroughServiceManager()) { 40 } 41 42 Lshal::Lshal(std::ostream &out, std::ostream &err, 43 sp<hidl::manager::V1_0::IServiceManager> serviceManager, 44 sp<hidl::manager::V1_0::IServiceManager> passthroughManager) 45 : mOut(out), mErr(err), 46 mServiceManager(serviceManager), 47 mPassthroughManager(passthroughManager) { 48 49 mRegisteredCommands.push_back({std::make_unique<ListCommand>(*this)}); 50 mRegisteredCommands.push_back({std::make_unique<DebugCommand>(*this)}); 51 mRegisteredCommands.push_back({std::make_unique<HelpCommand>(*this)}); 52 } 53 54 void Lshal::forEachCommand(const std::function<void(const Command* c)>& f) const { 55 for (const auto& e : mRegisteredCommands) f(e.get()); 56 } 57 58 void Lshal::usage() { 59 err() << "lshal: List and debug HALs." << std::endl << std::endl 60 << "commands:" << std::endl; 61 62 size_t nameMaxLength = 0; 63 forEachCommand([&](const Command* e) { 64 nameMaxLength = std::max(nameMaxLength, e->getName().length()); 65 }); 66 bool first = true; 67 forEachCommand([&](const Command* e) { 68 if (!first) err() << std::endl; 69 first = false; 70 err() << " " << std::left << std::setw(nameMaxLength + 8) << e->getName() 71 << e->getSimpleDescription(); 72 }); 73 err() << std::endl << "If no command is specified, `" << ListCommand::GetName() 74 << "` is the default." << std::endl << std::endl; 75 76 first = true; 77 forEachCommand([&](const Command* e) { 78 if (!first) err() << std::endl; 79 first = false; 80 e->usage(); 81 }); 82 } 83 84 // A unique_ptr type using a custom deleter function. 85 template<typename T> 86 using deleted_unique_ptr = std::unique_ptr<T, std::function<void(T *)> >; 87 88 static hardware::hidl_vec<hardware::hidl_string> convert(const std::vector<std::string> &v) { 89 hardware::hidl_vec<hardware::hidl_string> hv; 90 hv.resize(v.size()); 91 for (size_t i = 0; i < v.size(); ++i) { 92 hv[i].setToExternal(v[i].c_str(), v[i].size()); 93 } 94 return hv; 95 } 96 97 Status Lshal::emitDebugInfo( 98 const std::string &interfaceName, 99 const std::string &instanceName, 100 const std::vector<std::string> &options, 101 bool excludesParentInstances, 102 std::ostream &out, 103 NullableOStream<std::ostream> err) const { 104 using android::hidl::base::V1_0::IBase; 105 using android::hardware::details::getDescriptor; 106 107 hardware::Return<sp<IBase>> retBase = serviceManager()->get(interfaceName, instanceName); 108 109 if (!retBase.isOk()) { 110 std::string msg = "Cannot get " + interfaceName + "/" + instanceName + ": " 111 + retBase.description(); 112 err << msg << std::endl; 113 LOG(ERROR) << msg; 114 return TRANSACTION_ERROR; 115 } 116 117 sp<IBase> base = retBase; 118 if (base == nullptr) { 119 std::string msg = interfaceName + "/" + instanceName + " does not exist, or " 120 + "no permission to connect."; 121 err << msg << std::endl; 122 LOG(ERROR) << msg; 123 return NO_INTERFACE; 124 } 125 126 if (excludesParentInstances) { 127 const std::string descriptor = getDescriptor(base.get()); 128 if (descriptor.empty()) { 129 std::string msg = interfaceName + "/" + instanceName + " getDescriptor failed"; 130 err << msg << std::endl; 131 LOG(ERROR) << msg; 132 } 133 if (descriptor != interfaceName) { 134 return OK; 135 } 136 } 137 138 PipeRelay relay(out); 139 140 if (relay.initCheck() != OK) { 141 std::string msg = "PipeRelay::initCheck() FAILED w/ " + std::to_string(relay.initCheck()); 142 err << msg << std::endl; 143 LOG(ERROR) << msg; 144 return IO_ERROR; 145 } 146 147 deleted_unique_ptr<native_handle_t> fdHandle( 148 native_handle_create(1 /* numFds */, 0 /* numInts */), 149 native_handle_delete); 150 151 fdHandle->data[0] = relay.fd(); 152 153 hardware::Return<void> ret = base->debug(fdHandle.get(), convert(options)); 154 155 if (!ret.isOk()) { 156 std::string msg = "debug() FAILED on " + interfaceName + "/" + instanceName + ": " 157 + ret.description(); 158 err << msg << std::endl; 159 LOG(ERROR) << msg; 160 return TRANSACTION_ERROR; 161 } 162 return OK; 163 } 164 165 Status Lshal::parseArgs(const Arg &arg) { 166 optind = 1; 167 if (optind >= arg.argc) { 168 // no options at all. 169 return OK; 170 } 171 mCommand = arg.argv[optind]; 172 if (selectCommand(mCommand) != nullptr) { 173 ++optind; 174 return OK; // mCommand is set correctly 175 } 176 177 if (mCommand.size() > 0 && mCommand[0] == '-') { 178 // first argument is an option, set command to "" (which is recognized as "list") 179 mCommand.clear(); 180 return OK; 181 } 182 183 err() << arg.argv[0] << ": unrecognized option `" << arg.argv[optind] << "'" << std::endl; 184 return USAGE; 185 } 186 187 void signalHandler(int sig) { 188 if (sig == SIGINT) { 189 int retVal; 190 pthread_exit(&retVal); 191 } 192 } 193 194 Command* Lshal::selectCommand(const std::string& command) const { 195 if (command.empty()) { 196 return selectCommand(ListCommand::GetName()); 197 } 198 for (const auto& e : mRegisteredCommands) { 199 if (e->getName() == command) { 200 return e.get(); 201 } 202 } 203 return nullptr; 204 } 205 206 Status Lshal::main(const Arg &arg) { 207 // Allow SIGINT to terminate all threads. 208 signal(SIGINT, signalHandler); 209 210 Status status = parseArgs(arg); 211 if (status != OK) { 212 usage(); 213 return status; 214 } 215 auto c = selectCommand(mCommand); 216 if (c == nullptr) { 217 // unknown command, print global usage 218 usage(); 219 return USAGE; 220 } 221 status = c->main(arg); 222 if (status == USAGE) { 223 // bad options. Run `lshal help ${mCommand}` instead. 224 // For example, `lshal --unknown-option` becomes `lshal help` (prints global help) 225 // and `lshal list --unknown-option` becomes `lshal help list` 226 auto&& help = selectCommand(HelpCommand::GetName()); 227 return static_cast<HelpCommand*>(help)->usageOfCommand(mCommand); 228 } 229 230 return status; 231 } 232 233 NullableOStream<std::ostream> Lshal::err() const { 234 return mErr; 235 } 236 NullableOStream<std::ostream> Lshal::out() const { 237 return mOut; 238 } 239 240 const sp<IServiceManager> &Lshal::serviceManager() const { 241 return mServiceManager; 242 } 243 244 const sp<IServiceManager> &Lshal::passthroughManager() const { 245 return mPassthroughManager; 246 } 247 248 } // namespace lshal 249 } // namespace android 250