diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/apex_update_listener/Android.bp | 50 | ||||
-rw-r--r-- | common/apex_update_listener/apex_update_listener.cc | 190 | ||||
-rw-r--r-- | common/apex_update_listener/apex_update_listener.h | 92 | ||||
-rw-r--r-- | common/apex_update_listener/apex_update_listener_test.cc | 114 | ||||
-rw-r--r-- | common/hal/google_camera_hal/zsl_snapshot_capture_session.cc | 2 | ||||
-rw-r--r-- | common/hal/hidl_service/Android.bp | 28 | ||||
-rw-r--r-- | common/hal/hidl_service/hidl_camera_build_version.inl | 6 | ||||
-rw-r--r-- | common/hal/hidl_service/libc_wrappers.cc | 205 | ||||
-rw-r--r-- | common/hal/hidl_service/service.cc | 24 | ||||
-rwxr-xr-x | common/hal/hidl_service/version_script.sh | 36 |
10 files changed, 744 insertions, 3 deletions
diff --git a/common/apex_update_listener/Android.bp b/common/apex_update_listener/Android.bp new file mode 100644 index 0000000..2c331d8 --- /dev/null +++ b/common/apex_update_listener/Android.bp @@ -0,0 +1,50 @@ +// This library is meant to be fairly independent, and dependencies were can be +// kept to a minimum so that it can be statically linked into both rlsservice +// and GCH + +cc_defaults { + name: "apex_update_listener_cc_defaults_internal", + host_supported: true, + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + "-Wthread-safety", + ], + shared_libs: [ + "libbase", + "liblog", + ], + static_libs: [ + "libtinyxml2", + ], + proprietary: true, + vendor: true, +} + +cc_defaults { + name: "apex_update_listener_cc_defaults_static", + static_libs: [ + "libtinyxml2", + "libapex_update_listener", + ], +} + +cc_library_static { + name: "libapex_update_listener", + defaults: ["apex_update_listener_cc_defaults_internal"], + srcs: ["apex_update_listener.cc"], + export_include_dirs: ["."], +} + +cc_test { + name: "libapex_update_listener_test", + defaults: ["apex_update_listener_cc_defaults_internal"], + gtest: true, + srcs: ["apex_update_listener_test.cc"], + static_libs: [ + "libgmock", + "libapex_update_listener", + ], + require_root: true, +} diff --git a/common/apex_update_listener/apex_update_listener.cc b/common/apex_update_listener/apex_update_listener.cc new file mode 100644 index 0000000..604f9d2 --- /dev/null +++ b/common/apex_update_listener/apex_update_listener.cc @@ -0,0 +1,190 @@ +#include "apex_update_listener.h" +#include <log/log.h> +#include <sys/inotify.h> +#include <sys/types.h> +#include <tinyxml2.h> +#include <fstream> +#include <sstream> +#include <streambuf> +#include <string> +#include <vector> + +#undef LOG_TAG +#define LOG_TAG "apex_update_listener" + +namespace { + +template <typename T> +std::string ToString(const T& value) { + std::stringstream stream; + stream << value; + return stream.str(); +} + +} // namespace + +ApexUpdateListener::ApexUpdateListener( + ApexUpdateListener::Sigil, const std::string& apex_name, + const std::string& apex_info_list_file_name, CallbackFunction callback, + int fd, int wd, std::set<Info> last_info) + : apex_name_(apex_name), + apex_info_list_file_name_(apex_info_list_file_name), + callback_function_(callback), + file_descriptor_(fd), + watch_descriptor_(wd), + last_info_(last_info), + thread_(&ApexUpdateListener::ThreadFunction, this) { +} + +ApexUpdateListener::~ApexUpdateListener() { + running_ = false; + if (watch_descriptor_ >= 0) { + inotify_rm_watch(file_descriptor_, watch_descriptor_); + } + if (file_descriptor_ >= 0) { + close(file_descriptor_); + } + if (thread_.joinable()) { + thread_.join(); + } +} +std::unique_ptr<ApexUpdateListener> ApexUpdateListener::Make( + const std::string& apex_name, CallbackFunction callback, + bool invoke_with_initial_version, + const std::string& apex_info_list_file_name) { + int file_descriptor = inotify_init(); + if (file_descriptor < 0) { + ALOGE("Failed to inotify_init(): %s (%d)", strerror(errno), errno); + return nullptr; + } + int watch_descriptor = inotify_add_watch( + file_descriptor, std::string(apex_info_list_file_name).c_str(), + IN_MODIFY | IN_CREATE | IN_DELETE); + if (watch_descriptor < 0) { + ALOGE("Failed to inotify_add_watch(%s): %s (%d)", + std::string(apex_info_list_file_name).c_str(), strerror(errno), errno); + close(file_descriptor); + return nullptr; + } + if (!callback) { + ALOGE("Called with null callback"); + return nullptr; + } + auto last_info = TrySlurpInfo(apex_name, apex_info_list_file_name); + if (!last_info.has_value()) { + ALOGE("Could not slurp info from %s for package %s", + std::string(apex_info_list_file_name).c_str(), + std::string(apex_name).c_str()); + return nullptr; + } + if (invoke_with_initial_version) { + callback(std::set<Info>(), *last_info); + } + + return std::make_unique<ApexUpdateListener>( + Sigil{}, apex_name, apex_info_list_file_name, callback, file_descriptor, + watch_descriptor, *last_info); +} + +std::optional<std::set<ApexUpdateListener::Info>> +ApexUpdateListener::TrySlurpInfo(const std::string& apex_name, + const std::string& apex_info_list_file_name) { + tinyxml2::XMLDocument xml_doc; + auto status = xml_doc.LoadFile(apex_info_list_file_name.c_str()); + if (status != tinyxml2::XML_SUCCESS) { + ALOGE("XML parsing failed: %d", status); + return std::nullopt; + } + tinyxml2::XMLElement* apex_info_list = + xml_doc.FirstChildElement("apex-info-list"); + if (!apex_info_list) { + ALOGE("XML did not contain apex-info-list"); + return std::nullopt; + } + std::set<ApexUpdateListener::Info> ret; + for (tinyxml2::XMLElement* apex_info = + apex_info_list->FirstChildElement("apex-info"); + apex_info != nullptr; + apex_info = apex_info->NextSiblingElement("apex-info")) { + if (apex_info->Attribute("moduleName", apex_name.c_str())) { + Info info{.module_name = apex_name.c_str()}; + auto module_path = apex_info->Attribute("modulePath"); + auto preinstalled_module_path = + apex_info->Attribute("preinstalledModulePath"); + auto version_code = apex_info->Attribute("versionCode"); + auto version_name = apex_info->Attribute("versionName"); + auto is_active = apex_info->Attribute("isActive"); + auto is_factory = apex_info->Attribute("isFactory"); + if (module_path) { + info.module_path = module_path; + } + if (preinstalled_module_path) { + info.preinstalled_module_path = preinstalled_module_path; + } + if (version_code) { + info.version_code = std::strtol(version_code, nullptr, 10); + } + if (version_name) { + info.version_name = version_name; + } + if (is_active) { + info.is_active = !strcmp(is_active, "true"); + } + if (is_factory) { + info.is_factory = !strcmp(is_factory, "true"); + } + ret.insert(info); + } + } + if (ret.size()) { + return ret; + } + ALOGE("XML did not contain any apex-info about %s", apex_name.c_str()); + return std::nullopt; +} + +void ApexUpdateListener::ThreadFunction() { + // Maximum number of events to read at a time + constexpr int event_number = 16; + std::vector<struct inotify_event> events(event_number); + do { + auto length = read(file_descriptor_, events.data(), + event_number * sizeof(inotify_event)); + if (length == -EINTR) { + continue; // Interrupted by signal, try again + } + if (length < 0 || !running_) { + if (running_) { + ALOGE("Error reading inotify event from '%s': %s (%d)", + apex_info_list_file_name_.c_str(), strerror(errno), errno); + } + return; + } + + for (size_t i = 0; i < length / sizeof(inotify_event); i++) { + struct inotify_event& event = events[i]; + + if (event.mask & IN_CREATE) { + ALOGI("%s created as %s", apex_info_list_file_name_.c_str(), + (event.mask & IN_ISDIR) ? "directory" : "file"); + } else if (event.mask & IN_DELETE) { + ALOGI("%s deleted as %s", apex_info_list_file_name_.c_str(), + (event.mask & IN_ISDIR) ? "directory" : "file"); + } else if (event.mask & IN_MODIFY) { + ALOGI("%s modified as %s", apex_info_list_file_name_.c_str(), + (event.mask & IN_ISDIR) ? "directory" : "file"); + } + // We don't really care how it was updated as long as it wasn't deleted + if (event.mask & IN_DELETE) { + continue; + } + auto info = TrySlurpInfo(apex_name_, apex_info_list_file_name_); + if (info.has_value()) { + if (*info != last_info_ && callback_function_) { + callback_function_(last_info_, *info); + last_info_ = *info; + } + } + } + } while (running_); +} diff --git a/common/apex_update_listener/apex_update_listener.h b/common/apex_update_listener/apex_update_listener.h new file mode 100644 index 0000000..6263144 --- /dev/null +++ b/common/apex_update_listener/apex_update_listener.h @@ -0,0 +1,92 @@ +#pragma once + +#include <set> +#include <sstream> +#include <string> +#include <string_view> +#include <thread> + +class ApexUpdateListener { + private: + struct Sigil {}; + + public: + // Information extracted from updated /apex/apex-info-list.xml + struct Info { + std::string module_name; + std::string module_path; + std::string preinstalled_module_path; + int64_t version_code; + std::string version_name; + bool is_factory; + bool is_active; + + auto AsTuple() const { + return std::make_tuple(is_active, is_factory, version_code, version_name, + module_path, preinstalled_module_path, module_name); + } + + bool operator<(const Info& other) const { + return AsTuple() < other.AsTuple(); + } + + bool operator==(const ApexUpdateListener::Info& other) const { + return !(other < *this) && !(*this < other); + } + bool operator!=(const ApexUpdateListener::Info& other) const { + return !(*this == other); + } + template <typename T> + friend auto& operator<<(T& stream, const ApexUpdateListener::Info& i) { + return stream << "{ moduleName: " << i.module_name + << ", modulePath: " << i.module_path + << ", preinstalledModulePath: " << i.preinstalled_module_path + << ", versionCode: " << i.version_code + << ", versionName: " << i.version_name + << ", i.isFactory: " << i.is_factory + << ", i.isActive: " << i.is_active << " }"; + } + template <typename T> + friend auto& operator<<(T& stream, + const std::set<ApexUpdateListener::Info>& s) { + stream << "{"; + std::string sep = ""; + for (auto& i : s) { + stream << sep << i; + sep = ", "; + } + return stream << "}"; + } + }; + + using CallbackFunction = + std::function<void(const std::set<Info>& last_versions, + const std::set<Info>& current_versions)>; + + ApexUpdateListener(Sigil, const std::string& apex_name, + const std::string& apex_info_list_file_name, + CallbackFunction callback, int fd, int wd, + std::set<Info> last_info); + + static std::unique_ptr<ApexUpdateListener> Make( + const std::string& apex_name, CallbackFunction callback, + bool invoke_with_initial_version = false, + const std::string& apex_info_list_file_name = "/apex/apex-info-list.xml"); + + // We need some cleanup handling + ~ApexUpdateListener(); + + private: + const std::string apex_name_; + const std::string apex_info_list_file_name_; + const CallbackFunction callback_function_; + std::atomic<bool> running_ = true; + int file_descriptor_ = -1; + int watch_descriptor_ = -1; + std::set<Info> last_info_; + std::thread thread_; + + void ThreadFunction(); + static std::optional<std::set<Info>> TrySlurpInfo( + const std::string& apex_name, const std::string& apex_info_list_file_name); +}; diff --git a/common/apex_update_listener/apex_update_listener_test.cc b/common/apex_update_listener/apex_update_listener_test.cc new file mode 100644 index 0000000..3747ce0 --- /dev/null +++ b/common/apex_update_listener/apex_update_listener_test.cc @@ -0,0 +1,114 @@ +#include "apex_update_listener.h" + +#include <android-base/file.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <log/log.h> +#include <fstream> +#include <iostream> +#include <set> +#include <thread> + +#undef LOG_TAG +#define LOG_TAG "apex_update_listener_test" + +namespace { + +using InfoSet = std::set<ApexUpdateListener::Info>; +using testing::MockFunction; +using testing::StrictMock; + +const std::string kApexInfoStateJustPreinstalled = R"xml( +<?xml version="1.0" encoding="utf-8"?> +<apex-info-list> + <apex-info moduleName="com.test.apex" modulePath="/vendor/apex/com.test.apex" preinstalledModulePath="/vendor/apex/com.test.apex" versionCode="100" versionName="" isFactory="true" isActive="true"></apex-info> +</apex-info-list> +)xml"; + +const std::string kApexInfoStateOneOnData = R"xml( +<?xml version="1.0" encoding="utf-8"?> +<apex-info-list> + <apex-info moduleName="com.test.apex" modulePath="/data/apex/com.test.apex@200" preinstalledModulePath="/vendor/apex/com.test.apex" versionCode="200" versionName="" isFactory="false" isActive="true"></apex-info> + <apex-info moduleName="com.test.apex" modulePath="/vendor/apex/com.test.apex" preinstalledModulePath="/vendor/apex/com.test.apex" versionCode="100" versionName="" isFactory="true" isActive="false"></apex-info> +</apex-info-list> +)xml"; + +void WriteStringToFile(const char* filename, const std::string& data) { + std::ofstream xml_stream(filename); + xml_stream.write(data.data(), data.size()); +} + +} // namespace + +TEST(ApexUpdateListener, InstallUpdate) { + TemporaryFile tmp_xml_file; + + StrictMock<MockFunction<ApexUpdateListener::CallbackFunction>> callback; + std::mutex mutex; + std::condition_variable wait_cv; + EXPECT_CALL( + callback, + Call(InfoSet{{.module_name = "com.test.apex", + .module_path = "/vendor/apex/com.test.apex", + .preinstalled_module_path = "/vendor/apex/com.test.apex", + .version_code = 100, + .version_name = "", + .is_factory = true, + .is_active = true}}, + InfoSet{{.module_name = "com.test.apex", + .module_path = "/vendor/apex/com.test.apex", + .preinstalled_module_path = "/vendor/apex/com.test.apex", + .version_code = 100, + .version_name = "", + .is_factory = true, + .is_active = false}, + {.module_name = "com.test.apex", + .module_path = "/data/apex/com.test.apex@200", + .preinstalled_module_path = "/vendor/apex/com.test.apex", + .version_code = 200, + .version_name = "", + .is_factory = false, + .is_active = true}})) + .WillOnce([&mutex, &wait_cv]() { + std::lock_guard<std::mutex> lock(mutex); + wait_cv.notify_one(); + }); + + WriteStringToFile(tmp_xml_file.path, kApexInfoStateJustPreinstalled); + std::unique_ptr<ApexUpdateListener> ptr = ApexUpdateListener::Make( + "com.test.apex", callback.AsStdFunction(), false, tmp_xml_file.path); + EXPECT_NE(ptr, nullptr); + WriteStringToFile(tmp_xml_file.path, kApexInfoStateOneOnData); + std::unique_lock<std::mutex> lock(mutex); + wait_cv.wait_for(lock, std::chrono::milliseconds(30000)); +} + +TEST(ApexUpdateListener, InvokeWithInitialVersion) { + TemporaryFile tmp_xml_file; + + StrictMock<MockFunction<ApexUpdateListener::CallbackFunction>> callback; + std::mutex mutex; + std::condition_variable wait_cv; + + EXPECT_CALL( + callback, + Call(InfoSet{}, + InfoSet{{.module_name = "com.test.apex", + .module_path = "/vendor/apex/com.test.apex", + .preinstalled_module_path = "/vendor/apex/com.test.apex", + .version_code = 100, + .version_name = "", + .is_factory = true, + .is_active = true}})) + .WillOnce([&mutex, &wait_cv]() { + std::lock_guard<std::mutex> lock(mutex); + wait_cv.notify_one(); + }); + + WriteStringToFile(tmp_xml_file.path, kApexInfoStateJustPreinstalled); + std::unique_ptr<ApexUpdateListener> ptr = ApexUpdateListener::Make( + "com.test.apex", callback.AsStdFunction(), true, tmp_xml_file.path); + EXPECT_NE(ptr, nullptr); + std::unique_lock<std::mutex> lock(mutex); + wait_cv.wait_for(lock, std::chrono::milliseconds(30000)); +} diff --git a/common/hal/google_camera_hal/zsl_snapshot_capture_session.cc b/common/hal/google_camera_hal/zsl_snapshot_capture_session.cc index 793e0df..195b5a0 100644 --- a/common/hal/google_camera_hal/zsl_snapshot_capture_session.cc +++ b/common/hal/google_camera_hal/zsl_snapshot_capture_session.cc @@ -785,4 +785,4 @@ void ZslSnapshotCaptureSession::NotifyHalMessage(const NotifyMessage& message) { } } // namespace google_camera_hal -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/common/hal/hidl_service/Android.bp b/common/hal/hidl_service/Android.bp index 8b5ed6f..c114b6c 100644 --- a/common/hal/hidl_service/Android.bp +++ b/common/hal/hidl_service/Android.bp @@ -46,9 +46,29 @@ gch_lazy_hal_cc_defaults { }, } +sh_binary_host { + name: "camera_hal_version_script", + src: "version_script.sh", + filename_from_src: true, +} + +cc_genrule { + name: "hidl_camera_build_version", + tools: [":camera_hal_version_script"], + cmd: "$(location :camera_hal_version_script) $(in) $(out)", + vendor: true, + srcs: [ + "hidl_camera_build_version.inl", + ], + out: ["hidl_camera_build_version.h"], +} + cc_defaults { name: "camera_service_defaults", - defaults: ["google_camera_hal_defaults"], + defaults: [ + "google_camera_hal_defaults", + "apex_update_listener_cc_defaults_static", + ], vendor: true, relative_install_path: "hw", srcs: [ @@ -58,8 +78,12 @@ cc_defaults { "hidl_profiler.cc", "hidl_thermal_utils.cc", "hidl_utils.cc", + "libc_wrappers.cc", "service.cc", ], + generated_headers: [ + "hidl_camera_build_version", + ], compile_multilib: "first", shared_libs: [ "android.hardware.camera.device@3.2", @@ -90,7 +114,7 @@ cc_defaults { static_libs: [ "android.hardware.camera.common@1.0-helper", ], - vintf_fragments: ["android.hardware.camera.provider@2.7-service-google.xml"] + vintf_fragments: ["android.hardware.camera.provider@2.7-service-google.xml"], } cc_binary { diff --git a/common/hal/hidl_service/hidl_camera_build_version.inl b/common/hal/hidl_service/hidl_camera_build_version.inl new file mode 100644 index 0000000..1d104c4 --- /dev/null +++ b/common/hal/hidl_service/hidl_camera_build_version.inl @@ -0,0 +1,6 @@ +#pragma once + +namespace { +constexpr const char* kAndroidBuildId = "{BUILD_ID}"; +constexpr int64_t kHalManifestBuildNumber = UINT64_C({BUILD_NUMBER}); +} diff --git a/common/hal/hidl_service/libc_wrappers.cc b/common/hal/hidl_service/libc_wrappers.cc new file mode 100644 index 0000000..45b260b --- /dev/null +++ b/common/hal/hidl_service/libc_wrappers.cc @@ -0,0 +1,205 @@ +#include <dirent.h> +#include <dlfcn.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <string> +#include <unordered_map> + +#define LOG_TAG "GCH_libc_wrappers" +#include <log/log.h> + +//#define MONITOR_FILE_OP + +#ifdef __ANDROID_APEX__ + +#ifdef MONITOR_FILE_OP + +using mkfifo_function_type = int (*)(const char*, mode_t); +using access_function_type = int (*)(const char*, int); +using mkdir_function_type = int (*)(const char*, mode_t); +using rmdir_function_type = int (*)(const char*); +using chdir_function_type = int (*)(const char*); +using link_function_type = int (*)(const char*, const char*); +using unlink_function_type = int (*)(const char*); +using rename_function_type = int (*)(const char*, const char*); +using stat_function_type = int (*)(const char*, struct stat*); +using chmod_function_type = int (*)(const char*, mode_t); +using chown_function_type = int (*)(const char*, uid_t, gid_t); +using utime_function_type = int (*)(const char*, struct utimbuf*); +using opendir_function_type = DIR* (*)(const char*); +using execl_function_type = int (*)(const char*, const char*, ...); +using execle_function_type = int (*)(const char*, const char*, ...); +using execlp_function_type = int (*)(const char*, const char*, ...); +using execv_function_type = int (*)(const char*, char* const[]); +using execvp_function_type = int (*)(const char*, char* const[]); +using openat_function_type = int (*)(int, const char*, int, ...); + +extern "C" int mkfifo(const char* pathname, mode_t mode) { + static auto real_function = + reinterpret_cast<mkfifo_function_type>(dlsym(RTLD_NEXT, "mkfifo")); + int ret = real_function(pathname, mode); + ALOGI("mkfifo (%s,%d) == %d", pathname, mode, ret); + return ret; +} +extern "C" int access(const char* pathname, int mode) { + static auto real_function = + reinterpret_cast<access_function_type>(dlsym(RTLD_NEXT, "access")); + int ret = real_function(pathname, mode); + ALOGI("access (%s,%d) == %d", pathname, mode, ret); + return ret; +} +extern "C" int mkdir(const char* pathname, mode_t mode) { + static auto real_function = + reinterpret_cast<mkdir_function_type>(dlsym(RTLD_NEXT, "mkdir")); + int ret = real_function(pathname, mode); + ALOGI("mkdir (%s,%d) == %d", pathname, mode, ret); + return ret; +} +extern "C" int rmdir(const char* pathname) { + static auto real_function = + reinterpret_cast<rmdir_function_type>(dlsym(RTLD_NEXT, "rmdir")); + int ret = real_function(pathname); + ALOGI("rmdir (%s) == %d", pathname, ret); + return ret; +} +extern "C" int chdir(const char* path) { + static auto real_function = + reinterpret_cast<chdir_function_type>(dlsym(RTLD_NEXT, "chdir")); + int ret = real_function(path); + ALOGI("chdir (%s) == %d", path, ret); + return ret; +} +extern "C" int link(const char* oldpath, const char* newpath) { + static auto real_function = + reinterpret_cast<link_function_type>(dlsym(RTLD_NEXT, "link")); + int ret = real_function(oldpath, newpath); + ALOGI("link (%s,%s) == %d", oldpath, newpath, ret); + return ret; +} +extern "C" int unlink(const char* pathname) { + static auto real_function = + reinterpret_cast<unlink_function_type>(dlsym(RTLD_NEXT, "unlink")); + int ret = real_function(pathname); + ALOGI("unlink (%s) == %d", pathname, ret); + return ret; +} +extern "C" int rename(const char* oldpath, const char* newpath) { + static auto real_function = + reinterpret_cast<rename_function_type>(dlsym(RTLD_NEXT, "rename")); + int ret = real_function(oldpath, newpath); + ALOGI("rename (%s,%s) == %d", oldpath, newpath, ret); + return ret; +} +extern "C" int stat(const char* file_name, struct stat* buf) { + static auto real_function = + reinterpret_cast<stat_function_type>(dlsym(RTLD_NEXT, "stat")); + int ret = real_function(file_name, buf); + ALOGI("stat (%s, %p) == %d", file_name, buf, ret); + return ret; +} +extern "C" int chmod(const char* path, mode_t mode) { + static auto real_function = + reinterpret_cast<chmod_function_type>(dlsym(RTLD_NEXT, "chmod")); + int ret = real_function(path, mode); + ALOGI("chmod (%s) == %d", path, ret); + return ret; +} +extern "C" int chown(const char* path, uid_t owner, gid_t group) { + static auto real_function = + reinterpret_cast<chown_function_type>(dlsym(RTLD_NEXT, "chown")); + int ret = real_function(path, owner, group); + ALOGI("chown (%s,%d,%d) == %d", path, owner, group, ret); + return ret; +} +extern "C" int utime(const char* filename, struct utimbuf* buf) { + static auto real_function = + reinterpret_cast<utime_function_type>(dlsym(RTLD_NEXT, "utime")); + int ret = real_function(filename, buf); + ALOGI("utime (%s, %p) == %d", filename, buf, ret); + return ret; +} +extern "C" DIR* opendir(const char* name) { + static auto real_function = + reinterpret_cast<opendir_function_type>(dlsym(RTLD_NEXT, "opendir")); + DIR* ret = real_function(name); + ALOGI("opendir (%s) == %p", name, ret); + return ret; +} +extern "C" int execl(const char* path, const char* arg, ...) { + static auto real_function = + reinterpret_cast<execl_function_type>(dlsym(RTLD_NEXT, "execl")); + int ret = real_function(path, arg); + ALOGI("execl (%s, %s) == %d", path, arg, ret); + return ret; +} +extern "C" int execle(const char* path, const char* arg, ...) { + static auto real_function = + reinterpret_cast<execle_function_type>(dlsym(RTLD_NEXT, "execle")); + int ret = real_function(path, arg); + ALOGI("execle (%s, %s) == %d", path, arg, ret); + return ret; +} +extern "C" int execlp(const char* file, const char* arg, ...) { + static auto real_function = + reinterpret_cast<execlp_function_type>(dlsym(RTLD_NEXT, "execlp")); + int ret = real_function(file, arg); + ALOGI("execlp %s, %s) == %d", file, arg, ret); + return ret; +} +extern "C" int execv(const char* path, char* const argv[]) { + static auto real_function = + reinterpret_cast<execv_function_type>(dlsym(RTLD_NEXT, "execv")); + int ret = real_function(path, argv); + ALOGI("execv (%s, %s, ...) == %d", path, argv[0], ret); + return ret; +} +extern "C" int execvp(const char* file, char* const argv[]) { + static auto real_function = + reinterpret_cast<execvp_function_type>(dlsym(RTLD_NEXT, "execvp")); + int ret = real_function(file, argv); + ALOGI("execvp (%s, %s,...) == %d", file, argv[0], ret); + return ret; +} + +extern "C" int openat(int dirfd, const char* pathname, int flags, ...) { + static auto real_function = + reinterpret_cast<openat_function_type>(dlsym(RTLD_NEXT, "openat")); + int ret = real_function(dirfd, pathname, flags); + ALOGI("openat(%d, %s, 0x%x) == %d", dirfd, pathname, flags, ret); + return ret; +} +#endif + +using dlopen_function_type = void* (*)(const char*, int); + +// This is a temporary workaround for prebuilts calling dlopen with absolute +// paths. +extern "C" void* dlopen(const char* filename, int flags) { + static auto real_dlopen_function = + reinterpret_cast<dlopen_function_type>(dlsym(RTLD_NEXT, "dlopen")); + if (!real_dlopen_function) { + ALOGE("Could not RTLD_NEXT dlopen, something very wrong."); + std::abort(); + } + void* ret = real_dlopen_function(filename, flags); + if (!ret) { + ALOGI("dlopen(%s) failed, seeing if we can fix it", filename); + std::string original_filename(filename); + + if (original_filename.find("/vendor/") == 0) { + std::string new_filename = "/apex/com.google.pixel.camera.hal/" + + original_filename.substr(strlen("/vendor/")); + ALOGI("Trying %s instead of %s\n", new_filename.c_str(), filename); + ret = real_dlopen_function(new_filename.c_str(), flags); + if (ret) { + ALOGE( + "ERROR: Update your code to not use absolute paths. dlopen(%s) " + "failed but dlopen(%s) succeeded instead.", + filename, new_filename.c_str()); + } + } + } + return ret; +} +#endif diff --git a/common/hal/hidl_service/service.cc b/common/hal/hidl_service/service.cc index c293c94..5acf397 100644 --- a/common/hal/hidl_service/service.cc +++ b/common/hal/hidl_service/service.cc @@ -21,12 +21,15 @@ #endif #include <android/hardware/camera/provider/2.7/ICameraProvider.h> +#include <apex_update_listener.h> #include <binder/ProcessState.h> +#include <cutils/properties.h> #include <hidl/HidlLazyUtils.h> #include <hidl/HidlTransportSupport.h> #include <malloc.h> #include <utils/Errors.h> +#include "hidl_camera_build_version.h" #include "hidl_camera_provider.h" using ::android::hardware::camera::provider::V2_7::ICameraProvider; @@ -47,6 +50,27 @@ int main() { android::hardware::configureRpcThreadpool(/*maxThreads=*/6, /*callerWillJoin=*/true); +#ifdef __ANDROID_APEX__ + int start_count = property_get_int32("vendor.camera.hal.start.count", 0); + property_set("vendor.camera.hal.start.count", + std::to_string(++start_count).c_str()); + property_set("vendor.camera.hal.version", + std::to_string(kHalManifestBuildNumber).c_str()); + property_set("vendor.camera.hal.build_id", kAndroidBuildId); + auto start_on_update = + ApexUpdateListener::Make("com.google.pixel.camera.hal", [](auto, auto) { + ALOGI("APEX version updated. starting."); + exit(0); + }); + ALOGI( + "Using ApexUpdateListener: %p Start Count: %d Current Version: %s " + "(%ld)", + start_on_update.get(), start_count, kAndroidBuildId, + kHalManifestBuildNumber); +#else + ALOGI("Not using ApexUpdateListener since not running in an apex."); +#endif + android::sp<ICameraProvider> camera_provider = HidlCameraProvider::Create(); if (camera_provider == nullptr) { return android::NO_INIT; diff --git a/common/hal/hidl_service/version_script.sh b/common/hal/hidl_service/version_script.sh new file mode 100755 index 0000000..2ab4e2b --- /dev/null +++ b/common/hal/hidl_service/version_script.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# +# This script generates the apex manifest version number (which is also used for +# the outer aab/jar object's version available to PackageManager). +# +# That version is limited to INT_MAX +# Strategy: +# if(local eng build) +# version = 2147480000 +# else +# version = numeric part of build number +# +# 2147480000 is chosen as being a value that can install over any expected build +# server build number that is still a little smaller than INT_MAX to leave room +# for maneuvering + +default_eng_build_number=2147480000 + +build_number=$(cat $OUT_DIR/soong/build_number.txt) +if [[ "$build_number" == "eng."* ]]; then + numeric_build_number=$default_eng_build_number +else + numeric_build_number=$(cat $OUT_DIR/soong/build_number.txt | tr -d -c 0-9) + if [[ -z "$numeric_build_number" ]]; then + numeric_build_number=$default_eng_build_number + fi + if ((numeric_build_number < 1)); then + numeric_build_number=1 + fi + if ((numeric_build_number >= default_eng_build_number)); then + numeric_build_number=$((default_eng_build_number-1)) + fi +fi + +cat $1 | sed -E "s/\{BUILD_NUMBER\}/$numeric_build_number/g" | sed -E "s/\{BUILD_ID\}/$build_number/g" > $2 + |