blob: 094e0b13f439f384dff639c75fa80b10345fa575 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "HidlSupport"
#include <hidl/HidlSupport.h>
#include <unordered_map>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <hidl-util/FQName.h>
#include <vintf/VendorManifest.h>
#include <vintf/parse_string.h>
#ifdef LIBHIDL_TARGET_DEBUGGABLE
#include <cutils/properties.h>
#include <dlfcn.h>
#include <regex>
#include <utility>
#endif
namespace android {
namespace hardware {
vintf::Transport getTransportForFrameworkPackages(const std::string &name) {
// TODO(b/34772739): check with VNDK team to see if this should be in an XML.
const static std::unordered_map<std::string, vintf::Transport> sTransports {
{"android.hidl.manager@1.0::IServiceManager", vintf::Transport::HWBINDER},
{"android.hidl.memory@1.0::IAllocator" , vintf::Transport::HWBINDER},
{"android.hidl.memory@1.0::IMapper" , vintf::Transport::PASSTHROUGH},
{"android.hidl.memory@1.0::IMemory" , vintf::Transport::PASSTHROUGH},
};
auto it = sTransports.find(name);
if (it == sTransports.end()) {
LOG(WARNING) << "getTransportForFrameworkPackages: Cannot find entry "
<< name << " in the static map.";
return vintf::Transport::EMPTY;
} else {
LOG(INFO) << "getTransportForFrameworkPackages: " << name
<< " declares transport method " << to_string(it->second);
}
return it->second;
}
vintf::Transport getTransportForHals(const FQName &fqName) {
const std::string package = fqName.package();
const vintf::VendorManifest *vm = vintf::VendorManifest::Get();
if (vm == nullptr) {
LOG(WARNING) << "getTransportFromManifest: Cannot find vendor interface manifest.";
return vintf::Transport::EMPTY;
}
size_t majorVer;
size_t minorVer;
if ( !::android::base::ParseUint(fqName.getPackageMajorVersion(), &majorVer)
|| !::android::base::ParseUint(fqName.getPackageMinorVersion(), &minorVer)) {
LOG(ERROR) << "getTransportFromManifest: " << fqName.string()
<< " does not specify a version.";
return vintf::Transport::EMPTY;
}
vintf::Transport tr = vm->getTransport(package, vintf::Version{majorVer, minorVer});
if (tr == vintf::Transport::EMPTY) {
LOG(WARNING) << "getTransportFromManifest: Cannot find entry "
<< package << fqName.atVersion() << " in vendor interface manifest.";
} else {
LOG(INFO) << "getTransportFromManifest: " << package << fqName.atVersion()
<< " declares transport method " << to_string(tr);
}
return tr;
}
vintf::Transport getTransport(const std::string &name) {
FQName fqName(name);
if (!fqName.isValid()) {
LOG(WARNING) << name << " is not a valid fully-qualified name.";
return vintf::Transport::EMPTY;
}
if (fqName.inPackage("android.hidl")) {
return getTransportForFrameworkPackages(name);
}
return getTransportForHals(fqName);
}
hidl_handle::hidl_handle() {
mHandle = nullptr;
mOwnsHandle = false;
}
hidl_handle::~hidl_handle() {
freeHandle();
}
hidl_handle::hidl_handle(const native_handle_t *handle) {
mHandle = handle;
mOwnsHandle = false;
}
// copy constructor.
hidl_handle::hidl_handle(const hidl_handle &other) {
mOwnsHandle = false;
*this = other;
}
// move constructor.
hidl_handle::hidl_handle(hidl_handle &&other) {
mOwnsHandle = false;
*this = std::move(other);
}
// assignment operators
hidl_handle &hidl_handle::operator=(const hidl_handle &other) {
if (this == &other) {
return *this;
}
freeHandle();
if (other.mHandle != nullptr) {
mHandle = native_handle_clone(other.mHandle);
if (mHandle == nullptr) {
LOG(FATAL) << "Failed to clone native_handle in hidl_handle.";
}
mOwnsHandle = true;
} else {
mHandle = nullptr;
mOwnsHandle = false;
}
return *this;
}
hidl_handle &hidl_handle::operator=(const native_handle_t *native_handle) {
freeHandle();
mHandle = native_handle;
mOwnsHandle = false;
return *this;
}
hidl_handle &hidl_handle::operator=(hidl_handle &&other) {
if (this != &other) {
freeHandle();
mHandle = other.mHandle;
mOwnsHandle = other.mOwnsHandle;
other.mHandle = nullptr;
other.mOwnsHandle = false;
}
return *this;
}
void hidl_handle::setTo(native_handle_t* handle, bool shouldOwn) {
mHandle = handle;
mOwnsHandle = shouldOwn;
}
const native_handle_t* hidl_handle::operator->() const {
return mHandle;
}
// implicit conversion to const native_handle_t*
hidl_handle::operator const native_handle_t *() const {
return mHandle;
}
// explicit conversion
const native_handle_t *hidl_handle::getNativeHandle() const {
return mHandle;
}
void hidl_handle::freeHandle() {
if (mOwnsHandle && mHandle != nullptr) {
// This can only be true if:
// 1. Somebody called setTo() with shouldOwn=true, so we know the handle
// wasn't const to begin with.
// 2. Copy/assignment from another hidl_handle, in which case we have
// cloned the handle.
// 3. Move constructor from another hidl_handle, in which case the original
// hidl_handle must have been non-const as well.
native_handle_t *handle = const_cast<native_handle_t*>(
static_cast<const native_handle_t*>(mHandle));
native_handle_close(handle);
native_handle_delete(handle);
mHandle = nullptr;
}
}
static const char *const kEmptyString = "";
hidl_string::hidl_string()
: mBuffer(kEmptyString),
mSize(0),
mOwnsBuffer(false) {
}
hidl_string::~hidl_string() {
clear();
}
hidl_string::hidl_string(const char *s) : hidl_string() {
copyFrom(s, strlen(s));
}
hidl_string::hidl_string(const char *s, size_t length) : hidl_string() {
copyFrom(s, length);
}
hidl_string::hidl_string(const hidl_string &other): hidl_string() {
copyFrom(other.c_str(), other.size());
}
hidl_string::hidl_string(const std::string &s) : hidl_string() {
copyFrom(s.c_str(), s.size());
}
hidl_string::hidl_string(hidl_string &&other): hidl_string() {
moveFrom(std::forward<hidl_string>(other));
}
hidl_string &hidl_string::operator=(hidl_string &&other) {
if (this != &other) {
clear();
moveFrom(std::forward<hidl_string>(other));
}
return *this;
}
hidl_string &hidl_string::operator=(const hidl_string &other) {
if (this != &other) {
clear();
copyFrom(other.c_str(), other.size());
}
return *this;
}
hidl_string &hidl_string::operator=(const char *s) {
clear();
copyFrom(s, strlen(s));
return *this;
}
hidl_string &hidl_string::operator=(const std::string &s) {
clear();
copyFrom(s.c_str(), s.size());
return *this;
}
bool hidl_string::operator< (const hidl_string &rhs) const {
return strcmp(mBuffer, rhs.mBuffer) < 0;
}
hidl_string::operator std::string() const {
return std::string(mBuffer, mSize);
}
hidl_string::operator const char *() const {
return mBuffer;
}
void hidl_string::copyFrom(const char *data, size_t size) {
// assume my resources are freed.
if (size > UINT32_MAX) {
LOG(FATAL) << "string size can't exceed 2^32 bytes.";
}
char *buf = (char *)malloc(size + 1);
memcpy(buf, data, size);
buf[size] = '\0';
mBuffer = buf;
mSize = static_cast<uint32_t>(size);
mOwnsBuffer = true;
}
void hidl_string::moveFrom(hidl_string &&other) {
// assume my resources are freed.
mBuffer = other.mBuffer;
mSize = other.mSize;
mOwnsBuffer = other.mOwnsBuffer;
other.mOwnsBuffer = false;
}
void hidl_string::clear() {
if (mOwnsBuffer && (mBuffer != kEmptyString)) {
free(const_cast<char *>(static_cast<const char *>(mBuffer)));
}
mBuffer = kEmptyString;
mSize = 0;
mOwnsBuffer = false;
}
void hidl_string::setToExternal(const char *data, size_t size) {
if (size > UINT32_MAX) {
LOG(FATAL) << "string size can't exceed 2^32 bytes.";
}
clear();
mBuffer = data;
mSize = static_cast<uint32_t>(size);
mOwnsBuffer = false;
}
const char *hidl_string::c_str() const {
return mBuffer;
}
size_t hidl_string::size() const {
return mSize;
}
bool hidl_string::empty() const {
return mSize == 0;
}
// ----------------------------------------------------------------------
// HidlInstrumentor implementation.
HidlInstrumentor::HidlInstrumentor(
const std::string &package,
const std::string &interface)
: mInstrumentationLibPackage(package), mInterfaceName(interface) {
configureInstrumentation(false);
}
HidlInstrumentor:: ~HidlInstrumentor() {}
void HidlInstrumentor::configureInstrumentation(bool log) {
bool enable_instrumentation = property_get_bool(
"hal.instrumentation.enable",
false);
if (enable_instrumentation != mEnableInstrumentation) {
mEnableInstrumentation = enable_instrumentation;
if (mEnableInstrumentation) {
if (log) {
LOG(INFO) << "Enable instrumentation.";
}
registerInstrumentationCallbacks (&mInstrumentationCallbacks);
} else {
if (log) {
LOG(INFO) << "Disable instrumentation.";
}
mInstrumentationCallbacks.clear();
}
}
}
void HidlInstrumentor::registerInstrumentationCallbacks(
std::vector<InstrumentationCallback> *instrumentationCallbacks) {
#ifdef LIBHIDL_TARGET_DEBUGGABLE
std::vector<std::string> instrumentationLibPaths;
char instrumentation_lib_path[PROPERTY_VALUE_MAX];
if (property_get("hal.instrumentation.lib.path",
instrumentation_lib_path,
"") > 0) {
instrumentationLibPaths.push_back(instrumentation_lib_path);
} else {
instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_SYSTEM);
instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_VENDOR);
instrumentationLibPaths.push_back(HAL_LIBRARY_PATH_ODM);
}
for (auto path : instrumentationLibPaths) {
DIR *dir = opendir(path.c_str());
if (dir == 0) {
LOG(WARNING) << path << " does not exist. ";
return;
}
struct dirent *file;
while ((file = readdir(dir)) != NULL) {
if (!isInstrumentationLib(file))
continue;
void *handle = dlopen((path + file->d_name).c_str(), RTLD_NOW);
char *error;
if (handle == nullptr) {
LOG(WARNING) << "couldn't load file: " << file->d_name
<< " error: " << dlerror();
continue;
}
dlerror(); /* Clear any existing error */
using cb_fun = void (*)(
const InstrumentationEvent,
const char *,
const char *,
const char *,
const char *,
std::vector<void *> *);
auto cb = (cb_fun)dlsym(handle,
("HIDL_INSTRUMENTATION_FUNCTION_" + mInterfaceName).c_str());
if ((error = dlerror()) != NULL) {
LOG(WARNING)
<< "couldn't find symbol: HIDL_INSTRUMENTATION_FUNCTION_"
<< mInterfaceName << ", error: " << error;
continue;
}
instrumentationCallbacks->push_back(cb);
LOG(INFO) << "Register instrumentation callback from "
<< file->d_name;
}
closedir(dir);
}
#else
// No-op for user builds.
return;
#endif
}
bool HidlInstrumentor::isInstrumentationLib(const dirent *file) {
#ifdef LIBHIDL_TARGET_DEBUGGABLE
if (file->d_type != DT_REG) return false;
std::cmatch cm;
std::regex e("^" + mInstrumentationLibPackage + "(.*).profiler.so$");
if (std::regex_match(file->d_name, cm, e)) return true;
#endif
return false;
}
} // namespace hardware
} // namespace android