summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuriy Romanenko <yromanenko@google.com>2021-07-02 23:48:56 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2021-07-02 23:48:56 +0000
commitb19183d577c67b2b631b73498cb04f73ecb9290e (patch)
tree1d1478168cfb7b0267ff1f55655fd8bd062c7ee7
parentf70a37f1ec38f77664ab0045e8b938a73b55c4f0 (diff)
parent620074ce3015070487c70aea75c110392905d217 (diff)
downloadcamera-b19183d577c67b2b631b73498cb04f73ecb9290e.tar.gz
Merge changes from topic "lyric-in-apex-again" into sc-dev
* changes: Added version/restart_count property setting to camera HAL Enable using apex listener in camera HAL lyric-in-apex implement apex update listener lib Temporary workaround for dlopen library paths
-rw-r--r--common/apex_update_listener/Android.bp50
-rw-r--r--common/apex_update_listener/apex_update_listener.cc190
-rw-r--r--common/apex_update_listener/apex_update_listener.h92
-rw-r--r--common/apex_update_listener/apex_update_listener_test.cc114
-rw-r--r--common/hal/google_camera_hal/zsl_snapshot_capture_session.cc2
-rw-r--r--common/hal/hidl_service/Android.bp28
-rw-r--r--common/hal/hidl_service/hidl_camera_build_version.inl6
-rw-r--r--common/hal/hidl_service/libc_wrappers.cc205
-rw-r--r--common/hal/hidl_service/service.cc24
-rwxr-xr-xcommon/hal/hidl_service/version_script.sh36
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
+