diff options
106 files changed, 5337 insertions, 2526 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index d950b7c287..4459cef655 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -91,7 +91,20 @@ on late-init chmod 0666 /sys/kernel/tracing/events/sync/enable chmod 0666 /sys/kernel/debug/tracing/events/fence/enable chmod 0666 /sys/kernel/tracing/events/fence/enable - + chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/enable + chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/enable + chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_grow/enable + chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_grow/enable + chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink/enable + chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_shrink/enable + chmod 0666 /sys/kernel/debug/tracing/events/signal/signal_generate/enable + chmod 0666 /sys/kernel/tracing/events/signal/signal_generate/enable + chmod 0666 /sys/kernel/debug/tracing/events/signal/signal_deliver/enable + chmod 0666 /sys/kernel/tracing/events/signal/signal_deliver/enable + chmod 0666 /sys/kernel/debug/tracing/events/mm_event/mm_event_record/enable + chmod 0666 /sys/kernel/tracing/events/mm_event/mm_event_record/enable + chmod 0666 /sys/kernel/debug/tracing/events/lowmemorykiller/lowmemory_kill/enable + chmod 0666 /sys/kernel/tracing/events/lowmemorykiller/lowmemory_kill/enable # disk chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable diff --git a/cmds/bugreportz/Android.bp b/cmds/bugreportz/Android.bp new file mode 100644 index 0000000000..924a3a351b --- /dev/null +++ b/cmds/bugreportz/Android.bp @@ -0,0 +1,44 @@ +// bugreportz +// ========== +cc_binary { + name: "bugreportz", + + srcs: [ + "bugreportz.cpp", + "main.cpp", + ], + + cflags: [ + "-Werror", + "-Wall", + ], + + shared_libs: [ + "libbase", + "libcutils", + ], +} + +// bugreportz_test +// =============== +cc_test { + name: "bugreportz_test", + test_suites: ["device-tests"], + + cflags: [ + "-Werror", + "-Wall", + ], + + srcs: [ + "bugreportz.cpp", + "bugreportz_test.cpp", + ], + + static_libs: ["libgmock"], + + shared_libs: [ + "libbase", + "libutils", + ], +} diff --git a/cmds/bugreportz/Android.mk b/cmds/bugreportz/Android.mk deleted file mode 100644 index 10dda56b75..0000000000 --- a/cmds/bugreportz/Android.mk +++ /dev/null @@ -1,44 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -# bugreportz -# ========== - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - bugreportz.cpp \ - main.cpp \ - -LOCAL_MODULE:= bugreportz - -LOCAL_CFLAGS := -Werror -Wall - -LOCAL_SHARED_LIBRARIES := \ - libbase \ - libcutils \ - -include $(BUILD_EXECUTABLE) - -# bugreportz_test -# =============== - -include $(CLEAR_VARS) - -LOCAL_MODULE := bugreportz_test -LOCAL_COMPATIBILITY_SUITE := device-tests -LOCAL_MODULE_TAGS := tests - -LOCAL_CFLAGS := -Werror -Wall - -LOCAL_SRC_FILES := \ - bugreportz.cpp \ - bugreportz_test.cpp \ - -LOCAL_STATIC_LIBRARIES := \ - libgmock \ - -LOCAL_SHARED_LIBRARIES := \ - libbase \ - libutils \ - -include $(BUILD_NATIVE_TEST) diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp new file mode 100644 index 0000000000..d91184a201 --- /dev/null +++ b/cmds/cmd/Android.bp @@ -0,0 +1,18 @@ +cc_binary { + name: "cmd", + + srcs: ["cmd.cpp"], + + shared_libs: [ + "libutils", + "liblog", + "libselinux", + "libbinder", + ], + + cflags: [ + "-Wall", + "-Werror", + "-DXP_UNIX", + ], +} diff --git a/cmds/cmd/Android.mk b/cmds/cmd/Android.mk deleted file mode 100644 index 4868555b34..0000000000 --- a/cmds/cmd/Android.mk +++ /dev/null @@ -1,25 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - cmd.cpp - -LOCAL_SHARED_LIBRARIES := \ - libutils \ - liblog \ - libselinux \ - libbinder - -LOCAL_CFLAGS := -Wall -Werror - -LOCAL_C_INCLUDES += \ - $(JNI_H_INCLUDE) - -ifeq ($(TARGET_OS),linux) - LOCAL_CFLAGS += -DXP_UNIX - #LOCAL_SHARED_LIBRARIES += librt -endif - -LOCAL_MODULE:= cmd - -include $(BUILD_EXECUTABLE) diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp index 260ea4b057..0ee6c3adac 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -24,10 +24,31 @@ #include "DumpstateInternal.h" +using android::base::StringPrintf; + namespace android { namespace os { namespace { + +static binder::Status exception(uint32_t code, const std::string& msg) { + MYLOGE("%s (%d) ", msg.c_str(), code); + return binder::Status::fromExceptionCode(code, String8(msg.c_str())); +} + +static binder::Status error(uint32_t code, const std::string& msg) { + MYLOGE("%s (%d) ", msg.c_str(), code); + return binder::Status::fromServiceSpecificError(code, String8(msg.c_str())); +} + +static void* callAndNotify(void* data) { + Dumpstate& ds = *static_cast<Dumpstate*>(data); + // TODO(111441001): Return status on listener. + ds.Run(); + MYLOGE("Finished Run()\n"); + return nullptr; +} + class DumpstateToken : public BnDumpstateToken {}; } @@ -77,37 +98,57 @@ binder::Status DumpstateService::setListener(const std::string& name, return binder::Status::ok(); } -binder::Status DumpstateService::startBugreport(int, const sp<IDumpstateListener>&, - const DumpstateOptions&, int32_t* returned_id) { - // TODO: fork to handle the bugreport request and return the process id or a request id here. +binder::Status DumpstateService::startBugreport(int, int bugreport_mode, int32_t* returned_id) { + // TODO(111441001): return a request id here. *returned_id = -1; + MYLOGI("startBugreport() with mode: %d\n", bugreport_mode); + + if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL && + bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE && + bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_REMOTE && + bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WEAR && + bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_TELEPHONY && + bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WIFI) { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Invalid bugreport mode: %d", bugreport_mode)); + } + + std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>(); + options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode)); + ds_.SetOptions(std::move(options)); + + pthread_t thread; + status_t err = pthread_create(&thread, nullptr, callAndNotify, &ds_); + if (err != 0) { + return error(err, "Could not create a background thread."); + } return binder::Status::ok(); } status_t DumpstateService::dump(int fd, const Vector<String16>&) { dprintf(fd, "id: %d\n", ds_.id_); dprintf(fd, "pid: %d\n", ds_.pid_); - dprintf(fd, "update_progress: %s\n", ds_.update_progress_ ? "true" : "false"); + dprintf(fd, "update_progress: %s\n", ds_.options_->do_progress_updates ? "true" : "false"); dprintf(fd, "update_progress_threshold: %d\n", ds_.update_progress_threshold_); dprintf(fd, "last_updated_progress: %d\n", ds_.last_updated_progress_); dprintf(fd, "progress:\n"); ds_.progress_->Dump(fd, " "); - dprintf(fd, "args: %s\n", ds_.args_.c_str()); - dprintf(fd, "extra_options: %s\n", ds_.extra_options_.c_str()); + dprintf(fd, "args: %s\n", ds_.options_->args.c_str()); + dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str()); dprintf(fd, "version: %s\n", ds_.version_.c_str()); dprintf(fd, "bugreport_dir: %s\n", ds_.bugreport_dir_.c_str()); dprintf(fd, "screenshot_path: %s\n", ds_.screenshot_path_.c_str()); dprintf(fd, "log_path: %s\n", ds_.log_path_.c_str()); dprintf(fd, "tmp_path: %s\n", ds_.tmp_path_.c_str()); dprintf(fd, "path: %s\n", ds_.path_.c_str()); - dprintf(fd, "extra_options: %s\n", ds_.extra_options_.c_str()); + dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str()); dprintf(fd, "base_name: %s\n", ds_.base_name_.c_str()); dprintf(fd, "name: %s\n", ds_.name_.c_str()); dprintf(fd, "now: %ld\n", ds_.now_); dprintf(fd, "is_zipping: %s\n", ds_.IsZipping() ? "true" : "false"); dprintf(fd, "listener: %s\n", ds_.listener_name_.c_str()); - dprintf(fd, "notification title: %s\n", ds_.notification_title.c_str()); - dprintf(fd, "notification description: %s\n", ds_.notification_description.c_str()); + dprintf(fd, "notification title: %s\n", ds_.options_->notification_title.c_str()); + dprintf(fd, "notification description: %s\n", ds_.options_->notification_description.c_str()); return NO_ERROR; } diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h index 131aff30a3..58095b38ff 100644 --- a/cmds/dumpstate/DumpstateService.h +++ b/cmds/dumpstate/DumpstateService.h @@ -41,8 +41,7 @@ class DumpstateService : public BinderService<DumpstateService>, public BnDumpst bool getSectionDetails, sp<IDumpstateToken>* returned_token) override; - binder::Status startBugreport(int fd, const sp<IDumpstateListener>& listener, - const DumpstateOptions& options, int32_t* returned_id) override; + binder::Status startBugreport(int fd, int bugreport_mode, int32_t* returned_id) override; private: Dumpstate& ds_; diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp index 600a500e86..97c8ae2045 100644 --- a/cmds/dumpstate/DumpstateUtil.cpp +++ b/cmds/dumpstate/DumpstateUtil.cpp @@ -101,13 +101,16 @@ CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::Al } CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRoot() { - values.account_mode_ = SU_ROOT; + if (!PropertiesHelper::IsUnroot()) { + values.account_mode_ = SU_ROOT; + } return *this; } CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRootIfAvailable() { - if (!PropertiesHelper::IsUserBuild()) - values.account_mode_ = SU_ROOT; + if (!PropertiesHelper::IsUserBuild()) { + return AsRoot(); + } return *this; } @@ -176,6 +179,7 @@ CommandOptions::CommandOptionsBuilder CommandOptions::WithTimeoutInMs(int64_t ti std::string PropertiesHelper::build_type_ = ""; int PropertiesHelper::dry_run_ = -1; +int PropertiesHelper::unroot_ = -1; bool PropertiesHelper::IsUserBuild() { if (build_type_.empty()) { @@ -191,6 +195,13 @@ bool PropertiesHelper::IsDryRun() { return dry_run_ == 1; } +bool PropertiesHelper::IsUnroot() { + if (unroot_ == -1) { + unroot_ = android::base::GetBoolProperty("dumpstate.unroot", false) ? 1 : 0; + } + return unroot_ == 1; +} + int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC))); if (fd.get() < 0) { diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h index 8342099821..d69ffbfc98 100644 --- a/cmds/dumpstate/DumpstateUtil.h +++ b/cmds/dumpstate/DumpstateUtil.h @@ -97,9 +97,16 @@ class CommandOptions { public: /* Sets the command to always run, even on `dry-run` mode. */ CommandOptionsBuilder& Always(); - /* Sets the command's PrivilegeMode as `SU_ROOT` */ + /* + * Sets the command's PrivilegeMode as `SU_ROOT` unless overridden by system property + * 'dumpstate.unroot'. + */ CommandOptionsBuilder& AsRoot(); - /* If !IsUserBuild(), sets the command's PrivilegeMode as `SU_ROOT` */ + /* + * Runs AsRoot() on userdebug builds. No-op on user builds since 'su' is + * not available. This is used for commands that return some useful information even + * when run as shell. + */ CommandOptionsBuilder& AsRootIfAvailable(); /* Sets the command's PrivilegeMode as `DROP_ROOT` */ CommandOptionsBuilder& DropRoot(); @@ -162,9 +169,17 @@ class PropertiesHelper { */ static bool IsDryRun(); + /** + * Checks whether root availability should be overridden. + * + * Useful to verify how dumpstate would work in a device with an user build. + */ + static bool IsUnroot(); + private: static std::string build_type_; static int dry_run_; + static int unroot_; }; /* diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md index 0302ea5f7d..d5b2953b5b 100644 --- a/cmds/dumpstate/README.md +++ b/cmds/dumpstate/README.md @@ -28,22 +28,22 @@ mmm -j frameworks/native/cmds/dumpstate && adb push ${OUT}/system/bin/dumpstate ## To build, deploy, and run unit tests -First create `/data/nativetest`: +First create `/data/nativetest64`: ``` -adb shell mkdir /data/nativetest +adb shell mkdir /data/nativetest64 ``` Then run: ``` -mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest/dumpstate_test* /data/nativetest && adb shell /data/nativetest/dumpstate_test/dumpstate_test +mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_test* /data/nativetest64 && adb shell /data/nativetest/dumpstate_test/dumpstate_test ``` And to run just one test (for example, `DumpstateTest.RunCommandNoArgs`): ``` -mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest/dumpstate_test* /data/nativetest && adb shell /data/nativetest/dumpstate_test/dumpstate_test --gtest_filter=DumpstateTest.RunCommandNoArgs +mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_test* /data/nativetest64 && adb shell /data/nativetest/dumpstate_test/dumpstate_test --gtest_filter=DumpstateTest.RunCommandNoArgs ``` ## To take quick bugreports @@ -52,6 +52,12 @@ mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest/dump adb shell setprop dumpstate.dry_run true ``` +## To emulate a device with user build + +``` +adb shell setprop dumpstate.unroot true +``` + ## To change the `dumpstate` version ``` diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl index 68a4f215e2..9e59f58aec 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl @@ -39,10 +39,27 @@ interface IDumpstate { IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener, boolean getSectionDetails); + // These modes encapsulate a set of run time options for generating bugreports. + // A zipped bugreport; default mode. + const int BUGREPORT_MODE_FULL = 0; + + // Interactive bugreport, i.e. triggered by the user. + const int BUGREPORT_MODE_INTERACTIVE = 1; + + // Remote bugreport triggered by DevicePolicyManager, for e.g. + const int BUGREPORT_MODE_REMOTE = 2; + + // Bugreport triggered on a wear device. + const int BUGREPORT_MODE_WEAR = 3; + + // Bugreport limited to only telephony info. + const int BUGREPORT_MODE_TELEPHONY = 4; + + // Bugreport limited to only wifi info. + const int BUGREPORT_MODE_WIFI = 5; + /* - * Starts a bugreport in a child process. - * - * Returns an identifier of the bugreport process running in the background. + * Starts a bugreport in the background. */ - int startBugreport(int fd, IDumpstateListener listener, in DumpstateOptions options); + int startBugreport(int fd, int bugreportMode); } diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 17bb7c3ed6..026c260818 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -682,7 +682,7 @@ void Dumpstate::PrintHeader() const { CommandOptions::WithTimeout(1).Always().Build()); printf("Bugreport format version: %s\n", version_.c_str()); printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_, - PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str()); + PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str()); printf("\n"); } @@ -1100,7 +1100,7 @@ static void RunDumpsysProto(const std::string& title, int priority, } } -// Runs dumpsys on services that must dump first and and will take less than 100ms to dump. +// Runs dumpsys on services that must dump first and will take less than 100ms to dump. static void RunDumpsysCritical() { RunDumpsysText("DUMPSYS CRITICAL", IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, /* timeout= */ 5s, /* service_timeout= */ 500ms); @@ -1623,7 +1623,7 @@ void Dumpstate::DumpstateBoard() { printf("*** See dumpstate-board.txt entry ***\n"); } -static void ShowUsageAndExit(int exitCode = 1) { +static void ShowUsageAndExit(int exit_code = 1) { fprintf(stderr, "usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-o file] [-d] [-p] " "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n" @@ -1643,7 +1643,7 @@ static void ShowUsageAndExit(int exitCode = 1) { " -R: take bugreport in remote mode (requires -o, -z, -d and -B, " "shouldn't be used with -P)\n" " -v: prints the dumpstate header and exit\n"); - exit(exitCode); + exit(exit_code); } static void ExitOnInvalidArgs() { @@ -1769,13 +1769,13 @@ static void Vibrate(int duration_ms) { * if we are writing zip files and adds the version file. */ static void PrepareToWriteToFile() { - const Dumpstate::DumpOptions& options = ds.options_; - ds.bugreport_dir_ = dirname(options.use_outfile.c_str()); + ds.bugreport_dir_ = dirname(ds.options_->use_outfile.c_str()); std::string build_id = android::base::GetProperty("ro.build.id", "UNKNOWN_BUILD"); std::string device_name = android::base::GetProperty("ro.product.name", "UNKNOWN_DEVICE"); - ds.base_name_ = android::base::StringPrintf("%s-%s-%s", basename(options.use_outfile.c_str()), - device_name.c_str(), build_id.c_str()); - if (options.do_add_date) { + ds.base_name_ = + android::base::StringPrintf("%s-%s-%s", basename(ds.options_->use_outfile.c_str()), + device_name.c_str(), build_id.c_str()); + if (ds.options_->do_add_date) { char date[80]; strftime(date, sizeof(date), "%Y-%m-%d-%H-%M-%S", localtime(&ds.now_)); ds.name_ = date; @@ -1783,13 +1783,13 @@ static void PrepareToWriteToFile() { ds.name_ = "undated"; } - if (options.telephony_only) { + if (ds.options_->telephony_only) { ds.base_name_ += "-telephony"; - } else if (options.wifi_only) { + } else if (ds.options_->wifi_only) { ds.base_name_ += "-wifi"; } - if (options.do_fb) { + if (ds.options_->do_fb) { ds.screenshot_path_ = ds.GetPath(".png"); } ds.tmp_path_ = ds.GetPath(".tmp"); @@ -1805,7 +1805,7 @@ static void PrepareToWriteToFile() { ds.bugreport_dir_.c_str(), ds.base_name_.c_str(), ds.name_.c_str(), ds.log_path_.c_str(), ds.tmp_path_.c_str(), ds.screenshot_path_.c_str()); - if (options.do_zip_file) { + if (ds.options_->do_zip_file) { ds.path_ = ds.GetPath(".zip"); MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str()); create_parent_dirs(ds.path_.c_str()); @@ -1824,7 +1824,6 @@ static void PrepareToWriteToFile() { * printing zipped file status, etc. */ static void FinalizeFile() { - const Dumpstate::DumpOptions& options = ds.options_; /* check if user changed the suffix using system properties */ std::string name = android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), ""); @@ -1853,23 +1852,12 @@ static void FinalizeFile() { } bool do_text_file = true; - if (options.do_zip_file) { + if (ds.options_->do_zip_file) { if (!ds.FinishZipFile()) { MYLOGE("Failed to finish zip file; sending text bugreport instead\n"); do_text_file = true; } else { do_text_file = false; - // Since zip file is already created, it needs to be renamed. - std::string new_path = ds.GetPath(".zip"); - if (ds.path_ != new_path) { - MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str()); - if (rename(ds.path_.c_str(), new_path.c_str())) { - MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(), - strerror(errno)); - } else { - ds.path_ = new_path; - } - } } } if (do_text_file) { @@ -1880,7 +1868,7 @@ static void FinalizeFile() { ds.path_.clear(); } } - if (options.use_control_socket) { + if (ds.options_->use_control_socket) { if (do_text_file) { dprintf(ds.control_socket_fd_, "FAIL:could not create zip file, check %s " @@ -1894,7 +1882,6 @@ static void FinalizeFile() { /* Broadcasts that we are done with the bugreport */ static void SendBugreportFinishedBroadcast() { - const Dumpstate::DumpOptions& options = ds.options_; if (!ds.path_.empty()) { MYLOGI("Final bugreport path: %s\n", ds.path_.c_str()); // clang-format off @@ -1908,22 +1895,22 @@ static void SendBugreportFinishedBroadcast() { "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_ }; // clang-format on - if (options.do_fb) { + if (ds.options_->do_fb) { am_args.push_back("--es"); am_args.push_back("android.intent.extra.SCREENSHOT"); am_args.push_back(ds.screenshot_path_); } - if (!ds.notification_title.empty()) { + if (!ds.options_->notification_title.empty()) { am_args.push_back("--es"); am_args.push_back("android.intent.extra.TITLE"); - am_args.push_back(ds.notification_title); - if (!ds.notification_description.empty()) { + am_args.push_back(ds.options_->notification_title); + if (!ds.options_->notification_description.empty()) { am_args.push_back("--es"); am_args.push_back("android.intent.extra.DESCRIPTION"); - am_args.push_back(ds.notification_description); + am_args.push_back(ds.options_->notification_description); } } - if (options.is_remote_mode) { + if (ds.options_->is_remote_mode) { am_args.push_back("--es"); am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH"); am_args.push_back(SHA256_file_hash(ds.path_)); @@ -1936,30 +1923,170 @@ static void SendBugreportFinishedBroadcast() { } } -int Dumpstate::ParseCommandlineOptions(int argc, char* argv[]) { - int ret = -1; // success +static inline const char* ModeToString(Dumpstate::BugreportMode mode) { + switch (mode) { + case Dumpstate::BugreportMode::BUGREPORT_FULL: + return "BUGREPORT_FULL"; + case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE: + return "BUGREPORT_INTERACTIVE"; + case Dumpstate::BugreportMode::BUGREPORT_REMOTE: + return "BUGREPORT_REMOTE"; + case Dumpstate::BugreportMode::BUGREPORT_WEAR: + return "BUGREPORT_WEAR"; + case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY: + return "BUGREPORT_TELEPHONY"; + case Dumpstate::BugreportMode::BUGREPORT_WIFI: + return "BUGREPORT_WIFI"; + } +} + +static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) { + switch (mode) { + case Dumpstate::BugreportMode::BUGREPORT_FULL: + options->do_broadcast = true; + options->do_fb = true; + break; + case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE: + // Currently, the dumpstate binder is only used by Shell to update progress. + options->do_start_service = true; + options->do_progress_updates = true; + options->do_fb = false; + options->do_broadcast = true; + break; + case Dumpstate::BugreportMode::BUGREPORT_REMOTE: + options->do_vibrate = false; + options->is_remote_mode = true; + options->do_fb = false; + options->do_broadcast = true; + break; + case Dumpstate::BugreportMode::BUGREPORT_WEAR: + options->do_start_service = true; + options->do_progress_updates = true; + options->do_zip_file = true; + options->do_fb = true; + options->do_broadcast = true; + break; + case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY: + options->telephony_only = true; + options->do_fb = true; + options->do_broadcast = true; + break; + case Dumpstate::BugreportMode::BUGREPORT_WIFI: + options->wifi_only = true; + options->do_zip_file = true; + options->do_fb = true; + options->do_broadcast = true; + break; + } +} + +static Dumpstate::BugreportMode getBugreportModeFromProperty() { + // If the system property is not set, it's assumed to be a full bugreport. + Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_FULL; + + std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, ""); + if (!extra_options.empty()) { + // Framework uses a system property to override some command-line args. + // Currently, it contains the type of the requested bugreport. + if (extra_options == "bugreportplus") { + mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE; + } else if (extra_options == "bugreportremote") { + mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE; + } else if (extra_options == "bugreportwear") { + mode = Dumpstate::BugreportMode::BUGREPORT_WEAR; + } else if (extra_options == "bugreporttelephony") { + mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY; + } else if (extra_options == "bugreportwifi") { + mode = Dumpstate::BugreportMode::BUGREPORT_WIFI; + } else { + MYLOGE("Unknown extra option: %s\n", extra_options.c_str()); + } + // Reset the property + android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, ""); + } + return mode; +} + +// TODO: Move away from system properties when we have options passed via binder calls. +/* Sets runtime options from the system properties and then clears those properties. */ +static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) { + Dumpstate::BugreportMode mode = getBugreportModeFromProperty(); + SetOptionsFromMode(mode, options); + + options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, ""); + if (!options->notification_title.empty()) { + // Reset the property + android::base::SetProperty(PROPERTY_EXTRA_TITLE, ""); + + options->notification_description = + android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, ""); + if (!options->notification_description.empty()) { + // Reset the property + android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, ""); + } + MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(), + options->notification_description.c_str()); + } +} + +static void LogDumpOptions(const Dumpstate::DumpOptions& options) { + MYLOGI("do_zip_file: %d\n", options.do_zip_file); + MYLOGI("do_add_date: %d\n", options.do_add_date); + MYLOGI("do_vibrate: %d\n", options.do_vibrate); + MYLOGI("use_socket: %d\n", options.use_socket); + MYLOGI("use_control_socket: %d\n", options.use_control_socket); + MYLOGI("do_fb: %d\n", options.do_fb); + MYLOGI("do_broadcast: %d\n", options.do_broadcast); + MYLOGI("is_remote_mode: %d\n", options.is_remote_mode); + MYLOGI("show_header_only: %d\n", options.show_header_only); + MYLOGI("do_start_service: %d\n", options.do_start_service); + MYLOGI("telephony_only: %d\n", options.telephony_only); + MYLOGI("wifi_only: %d\n", options.wifi_only); + MYLOGI("do_progress_updates: %d\n", options.do_progress_updates); + MYLOGI("use_outfile: %s\n", options.use_outfile.c_str()); + MYLOGI("extra_options: %s\n", options.extra_options.c_str()); + MYLOGI("args: %s\n", options.args.c_str()); + MYLOGI("notification_title: %s\n", options.notification_title.c_str()); + MYLOGI("notification_description: %s\n", options.notification_description.c_str()); +} + +void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode) { + // In the new API world, date is always added; output is always a zip file. + // TODO(111441001): remove these options once they are obsolete. + do_add_date = true; + do_zip_file = true; + + // STOPSHIP b/111441001: Remove hardcoded output file path; accept fd. + use_outfile = "/data/user_de/0/com.android.shell/files/bugreports/bugreport"; + + extra_options = ModeToString(bugreport_mode); + SetOptionsFromMode(bugreport_mode, this); +} + +Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) { + RunStatus status = RunStatus::OK; int c; while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) { switch (c) { // clang-format off - case 'd': options_.do_add_date = true; break; - case 'z': options_.do_zip_file = true; break; - case 'o': options_.use_outfile = optarg; break; - case 's': options_.use_socket = true; break; - case 'S': options_.use_control_socket = true; break; - case 'v': options_.show_header_only = true; break; - case 'q': options_.do_vibrate = false; break; - case 'p': options_.do_fb = true; break; - case 'P': update_progress_ = true; break; - case 'R': options_.is_remote_mode = true; break; - case 'B': options_.do_broadcast = true; break; - case 'V': break; // compatibility no-op + case 'd': do_add_date = true; break; + case 'z': do_zip_file = true; break; + case 'o': use_outfile = optarg; break; + case 's': use_socket = true; break; + case 'S': use_control_socket = true; break; + case 'v': show_header_only = true; break; + case 'q': do_vibrate = false; break; + case 'p': do_fb = true; break; + case 'P': do_progress_updates = true; break; + case 'R': is_remote_mode = true; break; + case 'B': do_broadcast = true; break; + case 'V': break; // compatibility no-op case 'h': - ret = 0; + status = RunStatus::HELP; break; default: fprintf(stderr, "Invalid option: %c\n", c); - ret = 1; + status = RunStatus::INVALID_INPUT; break; // clang-format on } @@ -1967,87 +2094,49 @@ int Dumpstate::ParseCommandlineOptions(int argc, char* argv[]) { // TODO: use helper function to convert argv into a string for (int i = 0; i < argc; i++) { - args_ += argv[i]; + args += argv[i]; if (i < argc - 1) { - args_ += " "; + args += " "; } } // Reset next index used by getopt so this can be called multiple times, for eg, in tests. optind = 1; - return ret; -} - -// TODO: Move away from system properties when we have binder. -void Dumpstate::SetOptionsFromProperties() { - extra_options_ = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, ""); - if (!extra_options_.empty()) { - // Framework uses a system property to override some command-line args. - // Currently, it contains the type of the requested bugreport. - if (extra_options_ == "bugreportplus") { - // Currently, the dumpstate binder is only used by Shell to update progress. - options_.do_start_service = true; - update_progress_ = true; - options_.do_fb = false; - } else if (extra_options_ == "bugreportremote") { - options_.do_vibrate = false; - options_.is_remote_mode = true; - options_.do_fb = false; - } else if (extra_options_ == "bugreportwear") { - options_.do_start_service = true; - update_progress_ = true; - options_.do_zip_file = true; - } else if (extra_options_ == "bugreporttelephony") { - options_.telephony_only = true; - } else if (extra_options_ == "bugreportwifi") { - options_.wifi_only = true; - options_.do_zip_file = true; - } else { - MYLOGE("Unknown extra option: %s\n", extra_options_.c_str()); - } - // Reset the property - android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, ""); - } - - notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, ""); - if (!notification_title.empty()) { - // Reset the property - android::base::SetProperty(PROPERTY_EXTRA_TITLE, ""); - notification_description = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, ""); - if (!notification_description.empty()) { - // Reset the property - android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, ""); - } - MYLOGD("notification (title: %s, description: %s)\n", notification_title.c_str(), - notification_description.c_str()); - } + SetOptionsFromProperties(this); + return status; } -bool Dumpstate::ValidateOptions() { - if ((options_.do_zip_file || options_.do_add_date || ds.update_progress_ || - options_.do_broadcast) && - options_.use_outfile.empty()) { +bool Dumpstate::DumpOptions::ValidateOptions() const { + if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) + && use_outfile.empty()) { return false; } - if (options_.use_control_socket && !options_.do_zip_file) { + if (use_control_socket && !do_zip_file) { return false; } - if (ds.update_progress_ && !options_.do_broadcast) { + if (do_progress_updates && !do_broadcast) { return false; } - if (options_.is_remote_mode && (ds.update_progress_ || !options_.do_broadcast || - !options_.do_zip_file || !options_.do_add_date)) { + if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) { return false; } return true; } -/* Main entry point for dumpstate. */ -int run_main(int argc, char* argv[]) { +void Dumpstate::SetOptions(std::unique_ptr<DumpOptions> options) { + options_ = std::move(options); +} + +Dumpstate::RunStatus Dumpstate::Run() { + if (!options_->ValidateOptions()) { + MYLOGE("Invalid options specified\n"); + LogDumpOptions(*options_); + return RunStatus::INVALID_INPUT; + } /* set as high priority, and protect from OOM killer */ setpriority(PRIO_PROCESS, 0, -20); @@ -2064,52 +2153,42 @@ int run_main(int argc, char* argv[]) { } } - int status = ds.ParseCommandlineOptions(argc, argv); - if (status != -1) { - ShowUsageAndExit(status); - } - ds.SetOptionsFromProperties(); - if (!ds.ValidateOptions()) { - ExitOnInvalidArgs(); - } - - if (ds.version_ == VERSION_DEFAULT) { - ds.version_ = VERSION_CURRENT; + if (version_ == VERSION_DEFAULT) { + version_ = VERSION_CURRENT; } - if (ds.version_ != VERSION_CURRENT && ds.version_ != VERSION_SPLIT_ANR) { + if (version_ != VERSION_CURRENT && version_ != VERSION_SPLIT_ANR) { MYLOGE("invalid version requested ('%s'); suppported values are: ('%s', '%s', '%s')\n", - ds.version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(), + version_.c_str(), VERSION_DEFAULT.c_str(), VERSION_CURRENT.c_str(), VERSION_SPLIT_ANR.c_str()); - exit(1); + return RunStatus::INVALID_INPUT; } - const Dumpstate::DumpOptions& options = ds.options_; - if (options.show_header_only) { - ds.PrintHeader(); - exit(0); + if (options_->show_header_only) { + PrintHeader(); + return RunStatus::OK; } // Redirect output if needed - bool is_redirecting = !options.use_socket && !options.use_outfile.empty(); + bool is_redirecting = !options_->use_socket && !options_->use_outfile.empty(); // TODO: temporarily set progress until it's part of the Dumpstate constructor - std::string stats_path = is_redirecting - ? android::base::StringPrintf("%s/dumpstate-stats.txt", - dirname(options.use_outfile.c_str())) - : ""; - ds.progress_.reset(new Progress(stats_path)); + std::string stats_path = + is_redirecting ? android::base::StringPrintf("%s/dumpstate-stats.txt", + dirname(options_->use_outfile.c_str())) + : ""; + progress_.reset(new Progress(stats_path)); /* gets the sequential id */ uint32_t last_id = android::base::GetIntProperty(PROPERTY_LAST_ID, 0); - ds.id_ = ++last_id; + id_ = ++last_id; android::base::SetProperty(PROPERTY_LAST_ID, std::to_string(last_id)); MYLOGI("begin\n"); register_sig_handler(); - if (options.do_start_service) { + if (options_->do_start_service) { MYLOGI("Starting 'dumpstate' service\n"); android::status_t ret; if ((ret = android::os::DumpstateService::Start()) != android::OK) { @@ -2121,43 +2200,43 @@ int run_main(int argc, char* argv[]) { MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n"); } - MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", ds.id_, ds.args_.c_str(), - ds.extra_options_.c_str()); + MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(), + options_->extra_options.c_str()); - MYLOGI("bugreport format version: %s\n", ds.version_.c_str()); + MYLOGI("bugreport format version: %s\n", version_.c_str()); - ds.do_early_screenshot_ = ds.update_progress_; + do_early_screenshot_ = options_->do_progress_updates; // If we are going to use a socket, do it as early as possible // to avoid timeouts from bugreport. - if (options.use_socket) { + if (options_->use_socket) { redirect_to_socket(stdout, "dumpstate"); } - if (options.use_control_socket) { + if (options_->use_control_socket) { MYLOGD("Opening control socket\n"); - ds.control_socket_fd_ = open_socket("dumpstate"); - ds.update_progress_ = 1; + control_socket_fd_ = open_socket("dumpstate"); + options_->do_progress_updates = 1; } if (is_redirecting) { PrepareToWriteToFile(); - if (ds.update_progress_) { - if (options.do_broadcast) { + if (options_->do_progress_updates) { + if (options_->do_broadcast) { // clang-format off std::vector<std::string> am_args = { "--receiver-permission", "android.permission.DUMP", - "--es", "android.intent.extra.NAME", ds.name_, - "--ei", "android.intent.extra.ID", std::to_string(ds.id_), - "--ei", "android.intent.extra.PID", std::to_string(ds.pid_), - "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()), + "--es", "android.intent.extra.NAME", name_, + "--ei", "android.intent.extra.ID", std::to_string(id_), + "--ei", "android.intent.extra.PID", std::to_string(pid_), + "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()), }; // clang-format on SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args); } - if (options.use_control_socket) { - dprintf(ds.control_socket_fd_, "BEGIN:%s\n", ds.path_.c_str()); + if (options_->use_control_socket) { + dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str()); } } } @@ -2169,23 +2248,23 @@ int run_main(int argc, char* argv[]) { fclose(cmdline); } - if (options.do_vibrate) { + if (options_->do_vibrate) { Vibrate(150); } - if (options.do_fb && ds.do_early_screenshot_) { - if (ds.screenshot_path_.empty()) { + if (options_->do_fb && do_early_screenshot_) { + if (screenshot_path_.empty()) { // should not have happened MYLOGE("INTERNAL ERROR: skipping early screenshot because path was not set\n"); } else { MYLOGI("taking early screenshot\n"); - ds.TakeScreenshot(); + TakeScreenshot(); } } - if (options.do_zip_file && ds.zip_file != nullptr) { - if (chown(ds.path_.c_str(), AID_SHELL, AID_SHELL)) { - MYLOGE("Unable to change ownership of zip file %s: %s\n", ds.path_.c_str(), + if (options_->do_zip_file && zip_file != nullptr) { + if (chown(path_.c_str(), AID_SHELL, AID_SHELL)) { + MYLOGE("Unable to change ownership of zip file %s: %s\n", path_.c_str(), strerror(errno)); } } @@ -2194,19 +2273,19 @@ int run_main(int argc, char* argv[]) { int dup_stderr_fd; if (is_redirecting) { TEMP_FAILURE_RETRY(dup_stderr_fd = dup(fileno(stderr))); - redirect_to_file(stderr, const_cast<char*>(ds.log_path_.c_str())); - if (chown(ds.log_path_.c_str(), AID_SHELL, AID_SHELL)) { - MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", - ds.log_path_.c_str(), strerror(errno)); + redirect_to_file(stderr, const_cast<char*>(log_path_.c_str())); + if (chown(log_path_.c_str(), AID_SHELL, AID_SHELL)) { + MYLOGE("Unable to change ownership of dumpstate log file %s: %s\n", log_path_.c_str(), + strerror(errno)); } TEMP_FAILURE_RETRY(dup_stdout_fd = dup(fileno(stdout))); /* TODO: rather than generating a text file now and zipping it later, it would be more efficient to redirect stdout to the zip entry directly, but the libziparchive doesn't support that option yet. */ - redirect_to_file(stdout, const_cast<char*>(ds.tmp_path_.c_str())); - if (chown(ds.tmp_path_.c_str(), AID_SHELL, AID_SHELL)) { + redirect_to_file(stdout, const_cast<char*>(tmp_path_.c_str())); + if (chown(tmp_path_.c_str(), AID_SHELL, AID_SHELL)) { MYLOGE("Unable to change ownership of temporary bugreport file %s: %s\n", - ds.tmp_path_.c_str(), strerror(errno)); + tmp_path_.c_str(), strerror(errno)); } } @@ -2216,18 +2295,18 @@ int run_main(int argc, char* argv[]) { // NOTE: there should be no stdout output until now, otherwise it would break the header. // In particular, DurationReport objects should be created passing 'title, NULL', so their // duration is logged into MYLOG instead. - ds.PrintHeader(); + PrintHeader(); - if (options.telephony_only) { + if (options_->telephony_only) { DumpstateTelephonyOnly(); - ds.DumpstateBoard(); - } else if (options.wifi_only) { + DumpstateBoard(); + } else if (options_->wifi_only) { DumpstateWifiOnly(); } else { // Dump state for the default case. This also drops root. if (!DumpstateDefault()) { // Something went wrong. - return -1; + return RunStatus::ERROR; } } @@ -2237,12 +2316,12 @@ int run_main(int argc, char* argv[]) { } /* rename or zip the (now complete) .tmp file to its final location */ - if (!options.use_outfile.empty()) { + if (!options_->use_outfile.empty()) { FinalizeFile(); } /* vibrate a few but shortly times to let user know it's finished */ - if (options.do_vibrate) { + if (options_->do_vibrate) { for (int i = 0; i < 3; i++) { Vibrate(75); usleep((75 + 50) * 1000); @@ -2250,26 +2329,52 @@ int run_main(int argc, char* argv[]) { } /* tell activity manager we're done */ - if (options.do_broadcast) { + if (options_->do_broadcast) { SendBugreportFinishedBroadcast(); } - MYLOGD("Final progress: %d/%d (estimated %d)\n", ds.progress_->Get(), ds.progress_->GetMax(), - ds.progress_->GetInitialMax()); - ds.progress_->Save(); - MYLOGI("done (id %d)\n", ds.id_); + MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(), + progress_->GetInitialMax()); + progress_->Save(); + MYLOGI("done (id %d)\n", id_); if (is_redirecting) { TEMP_FAILURE_RETRY(dup2(dup_stderr_fd, fileno(stderr))); } - if (options.use_control_socket && ds.control_socket_fd_ != -1) { + if (options_->use_control_socket && control_socket_fd_ != -1) { MYLOGD("Closing control socket\n"); - close(ds.control_socket_fd_); + close(control_socket_fd_); } - ds.tombstone_data_.clear(); - ds.anr_data_.clear(); + tombstone_data_.clear(); + anr_data_.clear(); + + return RunStatus::OK; +} +/* Main entry point for dumpstate. */ +int run_main(int argc, char* argv[]) { + std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>(); + Dumpstate::RunStatus status = options->Initialize(argc, argv); + if (status == Dumpstate::RunStatus::OK) { + ds.SetOptions(std::move(options)); + status = ds.Run(); + } + + switch (status) { + case Dumpstate::RunStatus::OK: + return 0; + break; + case Dumpstate::RunStatus::HELP: + ShowUsageAndExit(0 /* exit code */); + break; + case Dumpstate::RunStatus::INVALID_INPUT: + ExitOnInvalidArgs(); + break; + case Dumpstate::RunStatus::ERROR: + exit(-1); + break; + } return 0; } diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 389cc2e218..35cbdb1096 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -27,6 +27,7 @@ #include <android-base/macros.h> #include <android-base/unique_fd.h> +#include <android/os/IDumpstate.h> #include <android/os/IDumpstateListener.h> #include <utils/StrongPointer.h> #include <ziparchive/zip_writer.h> @@ -42,6 +43,9 @@ // TODO: and then remove explicitly android::os::dumpstate:: prefixes namespace android { namespace os { + +struct DumpstateOptions; + namespace dumpstate { class DumpstateTest; @@ -183,6 +187,18 @@ class Dumpstate { friend class DumpstateTest; public: + enum RunStatus { OK, HELP, INVALID_INPUT, ERROR }; + + // The mode under which the bugreport should be run. Each mode encapsulates a few options. + enum BugreportMode { + BUGREPORT_FULL = android::os::IDumpstate::BUGREPORT_MODE_FULL, + BUGREPORT_INTERACTIVE = android::os::IDumpstate::BUGREPORT_MODE_INTERACTIVE, + BUGREPORT_REMOTE = android::os::IDumpstate::BUGREPORT_MODE_REMOTE, + BUGREPORT_WEAR = android::os::IDumpstate::BUGREPORT_MODE_WEAR, + BUGREPORT_TELEPHONY = android::os::IDumpstate::BUGREPORT_MODE_TELEPHONY, + BUGREPORT_WIFI = android::os::IDumpstate::BUGREPORT_MODE_WIFI + }; + static android::os::dumpstate::CommandOptions DEFAULT_DUMPSYS; static Dumpstate& GetInstance(); @@ -245,7 +261,7 @@ class Dumpstate { std::chrono::milliseconds timeout); /* - * Adds a text entry entry to the existing zip file. + * Adds a text entry to the existing zip file. */ bool AddTextZipEntry(const std::string& entry_name, const std::string& content); @@ -290,22 +306,15 @@ class Dumpstate { /* Returns true if the current version supports priority dump feature. */ bool CurrentVersionSupportsPriorityDumps() const; - // TODO: revisit the return values later. - /* - * Parses commandline arguments and sets runtime options accordingly. - * - * Returns 0 or positive number if the caller should exit with returned value as - * exit code, or returns -1 if caller should proceed with execution. - */ - int ParseCommandlineOptions(int argc, char* argv[]); + struct DumpOptions; - /* Sets runtime options from the system properties. */ - void SetOptionsFromProperties(); + /* Main entry point for running a complete bugreport. */ + RunStatus Run(); - /* Returns true if the options set so far are consistent. */ - bool ValidateOptions(); + /* Sets runtime options. */ + void SetOptions(std::unique_ptr<DumpOptions> options); - // TODO: add update_progress_ & other options from DumpState. + // TODO: add other options from DumpState. /* * Structure to hold options that determine the behavior of dumpstate. */ @@ -322,7 +331,26 @@ class Dumpstate { bool do_start_service = false; bool telephony_only = false; bool wifi_only = false; + // Whether progress updates should be published. + bool do_progress_updates = false; std::string use_outfile; + // TODO: rename to MODE. + // Extra options passed as system property. + std::string extra_options; + // Command-line arguments as string + std::string args; + // Notification title and description + std::string notification_title; + std::string notification_description; + + /* Initializes options from commandline arguments and system properties. */ + RunStatus Initialize(int argc, char* argv[]); + + /* Initializes options from the requested mode. */ + void Initialize(BugreportMode bugreport_mode); + + /* Returns true if the options set so far are consistent. */ + bool ValidateOptions() const; }; // TODO: initialize fields on constructor @@ -333,10 +361,7 @@ class Dumpstate { pid_t pid_; // Runtime options. - DumpOptions options_; - - // Whether progress updates should be published. - bool update_progress_ = false; + std::unique_ptr<DumpOptions> options_; // How frequently the progess should be updated;the listener will only be notificated when the // delta from the previous update is more than the threshold. @@ -356,12 +381,6 @@ class Dumpstate { // Bugreport format version; std::string version_ = VERSION_CURRENT; - // Command-line arguments as string - std::string args_; - - // Extra options passed as system property. - std::string extra_options_; - // Full path of the directory where the bugreport files will be written. std::string bugreport_dir_; @@ -398,10 +417,6 @@ class Dumpstate { std::string listener_name_; bool report_section_; - // Notification title and description - std::string notification_title; - std::string notification_description; - // List of open tombstone dump files. std::vector<DumpData> tombstone_data_; diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index c57535a6c1..9ca894d7ae 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -85,6 +85,10 @@ class DumpstateBaseTest : public Test { PropertiesHelper::build_type_ = build_type; } + void SetUnroot(bool unroot) const { + PropertiesHelper::unroot_ = unroot; + } + bool IsStandalone() const { return calls_ == 1; } @@ -137,96 +141,43 @@ class DumpstateBaseTest : public Test { } }; -class DumpstateTest : public DumpstateBaseTest { +class DumpOptionsTest : public Test { public: - void SetUp() { - DumpstateBaseTest::SetUp(); - SetDryRun(false); - SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)")); - ds.progress_.reset(new Progress()); - ds.update_progress_ = false; - ds.update_progress_threshold_ = 0; - ds.options_ = Dumpstate::DumpOptions(); + virtual ~DumpOptionsTest() { } - - // Runs a command and capture `stdout` and `stderr`. - int RunCommand(const std::string& title, const std::vector<std::string>& full_command, - const CommandOptions& options = CommandOptions::DEFAULT) { - CaptureStdout(); - CaptureStderr(); - int status = ds.RunCommand(title, full_command, options); - out = GetCapturedStdout(); - err = GetCapturedStderr(); - return status; + virtual void SetUp() { + options_ = Dumpstate::DumpOptions(); } - // Dumps a file and capture `stdout` and `stderr`. - int DumpFile(const std::string& title, const std::string& path) { - CaptureStdout(); - CaptureStderr(); - int status = ds.DumpFile(title, path); - out = GetCapturedStdout(); - err = GetCapturedStderr(); - return status; - } - - void SetProgress(long progress, long initial_max, long threshold = 0) { - ds.update_progress_ = true; - ds.update_progress_threshold_ = threshold; - ds.last_updated_progress_ = 0; - ds.progress_.reset(new Progress(initial_max, progress, 1.2)); - } - - std::string GetProgressMessage(const std::string& listener_name, int progress, int max, - int old_max = 0, bool update_progress = true) { - EXPECT_EQ(progress, ds.progress_->Get()) << "invalid progress"; - EXPECT_EQ(max, ds.progress_->GetMax()) << "invalid max"; - - bool max_increased = old_max > 0; - - std::string message = ""; - if (max_increased) { - message = - android::base::StringPrintf("Adjusting max progress from %d to %d\n", old_max, max); - } - - if (update_progress) { - message += android::base::StringPrintf("Setting progress (%s): %d/%d\n", - listener_name.c_str(), progress, max); - } - - return message; - } - - // `stdout` and `stderr` from the last command ran. - std::string out, err; - - Dumpstate& ds = Dumpstate::GetInstance(); + Dumpstate::DumpOptions options_; }; -TEST_F(DumpstateTest, ParseCommandlineOptionsNone) { +TEST_F(DumpOptionsTest, InitializeNone) { // clang-format off char* argv[] = { const_cast<char*>("dumpstate") }; // clang-format on - int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv); - EXPECT_EQ(-1, ret); - EXPECT_FALSE(ds.options_.do_add_date); - EXPECT_FALSE(ds.options_.do_zip_file); - EXPECT_EQ("", ds.options_.use_outfile); - EXPECT_FALSE(ds.options_.use_socket); - EXPECT_FALSE(ds.options_.use_control_socket); - EXPECT_FALSE(ds.options_.show_header_only); - EXPECT_TRUE(ds.options_.do_vibrate); - EXPECT_FALSE(ds.options_.do_fb); - EXPECT_FALSE(ds.update_progress_); - EXPECT_FALSE(ds.options_.is_remote_mode); - EXPECT_FALSE(ds.options_.do_broadcast); -} - -TEST_F(DumpstateTest, ParseCommandlineOptionsPartial1) { + Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv); + + EXPECT_EQ(status, Dumpstate::RunStatus::OK); + + // These correspond to bugreport_mode = full, because that's the default. + EXPECT_FALSE(options_.do_add_date); + EXPECT_FALSE(options_.do_zip_file); + EXPECT_EQ("", options_.use_outfile); + EXPECT_FALSE(options_.use_socket); + EXPECT_FALSE(options_.use_control_socket); + EXPECT_FALSE(options_.show_header_only); + EXPECT_TRUE(options_.do_vibrate); + EXPECT_TRUE(options_.do_fb); + EXPECT_FALSE(options_.do_progress_updates); + EXPECT_FALSE(options_.is_remote_mode); + EXPECT_TRUE(options_.do_broadcast); +} + +TEST_F(DumpOptionsTest, InitializePartial1) { // clang-format off char* argv[] = { const_cast<char*>("dumpstate"), @@ -238,25 +189,27 @@ TEST_F(DumpstateTest, ParseCommandlineOptionsPartial1) { }; // clang-format on - int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv); - EXPECT_EQ(-1, ret); - EXPECT_TRUE(ds.options_.do_add_date); - EXPECT_TRUE(ds.options_.do_zip_file); + + Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv); + + EXPECT_EQ(status, Dumpstate::RunStatus::OK); + EXPECT_TRUE(options_.do_add_date); + EXPECT_TRUE(options_.do_zip_file); // TODO: Maybe we should trim the filename - EXPECT_EQ(" abc", std::string(ds.options_.use_outfile)); - EXPECT_TRUE(ds.options_.use_socket); - EXPECT_TRUE(ds.options_.use_control_socket); + EXPECT_EQ(" abc", std::string(options_.use_outfile)); + EXPECT_TRUE(options_.use_socket); + EXPECT_TRUE(options_.use_control_socket); // Other options retain default values - EXPECT_FALSE(ds.options_.show_header_only); - EXPECT_TRUE(ds.options_.do_vibrate); - EXPECT_FALSE(ds.options_.do_fb); - EXPECT_FALSE(ds.update_progress_); - EXPECT_FALSE(ds.options_.is_remote_mode); - EXPECT_FALSE(ds.options_.do_broadcast); + EXPECT_FALSE(options_.show_header_only); + EXPECT_TRUE(options_.do_vibrate); + EXPECT_TRUE(options_.do_fb); + EXPECT_FALSE(options_.do_progress_updates); + EXPECT_FALSE(options_.is_remote_mode); + EXPECT_TRUE(options_.do_broadcast); } -TEST_F(DumpstateTest, ParseCommandlineOptionsPartial2) { +TEST_F(DumpOptionsTest, InitializePartial2) { // clang-format off char* argv[] = { const_cast<char*>("dumpstate"), @@ -268,93 +221,162 @@ TEST_F(DumpstateTest, ParseCommandlineOptionsPartial2) { const_cast<char*>("-B"), }; // clang-format on - int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv); - EXPECT_EQ(-1, ret); - EXPECT_TRUE(ds.options_.show_header_only); - EXPECT_FALSE(ds.options_.do_vibrate); - EXPECT_TRUE(ds.options_.do_fb); - EXPECT_TRUE(ds.update_progress_); - EXPECT_TRUE(ds.options_.is_remote_mode); - EXPECT_TRUE(ds.options_.do_broadcast); + + Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv); + + EXPECT_EQ(status, Dumpstate::RunStatus::OK); + EXPECT_TRUE(options_.show_header_only); + EXPECT_FALSE(options_.do_vibrate); + EXPECT_TRUE(options_.do_fb); + EXPECT_TRUE(options_.do_progress_updates); + EXPECT_TRUE(options_.is_remote_mode); + EXPECT_TRUE(options_.do_broadcast); // Other options retain default values - EXPECT_FALSE(ds.options_.do_add_date); - EXPECT_FALSE(ds.options_.do_zip_file); - EXPECT_EQ("", ds.options_.use_outfile); - EXPECT_FALSE(ds.options_.use_socket); - EXPECT_FALSE(ds.options_.use_control_socket); + EXPECT_FALSE(options_.do_add_date); + EXPECT_FALSE(options_.do_zip_file); + EXPECT_EQ("", options_.use_outfile); + EXPECT_FALSE(options_.use_socket); + EXPECT_FALSE(options_.use_control_socket); } -TEST_F(DumpstateTest, ParseCommandlineOptionsHelp) { +TEST_F(DumpOptionsTest, InitializeHelp) { // clang-format off char* argv[] = { const_cast<char*>("dumpstate"), const_cast<char*>("-h") }; // clang-format on - int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv); - // -h is for help. Caller exit with code = 0 after printing usage, so expect return = 0. - EXPECT_EQ(0, ret); + Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv); + + // -h is for help. + EXPECT_EQ(status, Dumpstate::RunStatus::HELP); } -TEST_F(DumpstateTest, ParseCommandlineOptionsUnknown) { +TEST_F(DumpOptionsTest, InitializeUnknown) { // clang-format off char* argv[] = { const_cast<char*>("dumpstate"), const_cast<char*>("-u") // unknown flag }; // clang-format on - int ret = ds.ParseCommandlineOptions(ARRAY_SIZE(argv), argv); - // -u is unknown. Caller exit with code = 1 to show execution failure, after printing usage, - // so expect return = 1. - EXPECT_EQ(1, ret); + Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv); + + // -u is unknown. + EXPECT_EQ(status, Dumpstate::RunStatus::INVALID_INPUT); } -TEST_F(DumpstateTest, ValidateOptionsNeedOutfile1) { - ds.options_.do_zip_file = true; - EXPECT_FALSE(ds.ValidateOptions()); - ds.options_.use_outfile = "a/b/c"; - EXPECT_TRUE(ds.ValidateOptions()); +TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile1) { + options_.do_zip_file = true; + EXPECT_FALSE(options_.ValidateOptions()); + options_.use_outfile = "a/b/c"; + EXPECT_TRUE(options_.ValidateOptions()); } -TEST_F(DumpstateTest, ValidateOptionsNeedOutfile2) { - ds.options_.do_broadcast = true; - EXPECT_FALSE(ds.ValidateOptions()); - ds.options_.use_outfile = "a/b/c"; - EXPECT_TRUE(ds.ValidateOptions()); +TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) { + options_.do_broadcast = true; + EXPECT_FALSE(options_.ValidateOptions()); + options_.use_outfile = "a/b/c"; + EXPECT_TRUE(options_.ValidateOptions()); } -TEST_F(DumpstateTest, ValidateOptionsNeedZipfile) { - ds.options_.use_control_socket = true; - EXPECT_FALSE(ds.ValidateOptions()); +TEST_F(DumpOptionsTest, ValidateOptionsNeedZipfile) { + options_.use_control_socket = true; + EXPECT_FALSE(options_.ValidateOptions()); - ds.options_.do_zip_file = true; - ds.options_.use_outfile = "a/b/c"; // do_zip_file needs outfile - EXPECT_TRUE(ds.ValidateOptions()); + options_.do_zip_file = true; + options_.use_outfile = "a/b/c"; // do_zip_file needs outfile + EXPECT_TRUE(options_.ValidateOptions()); } -TEST_F(DumpstateTest, ValidateOptionsUpdateProgressNeedsBroadcast) { - ds.update_progress_ = true; - ds.options_.use_outfile = "a/b/c"; // update_progress_ needs outfile - EXPECT_FALSE(ds.ValidateOptions()); +TEST_F(DumpOptionsTest, ValidateOptionsUpdateProgressNeedsBroadcast) { + options_.do_progress_updates = true; + options_.use_outfile = "a/b/c"; // do_progress_updates needs outfile + EXPECT_FALSE(options_.ValidateOptions()); - ds.options_.do_broadcast = true; - EXPECT_TRUE(ds.ValidateOptions()); + options_.do_broadcast = true; + EXPECT_TRUE(options_.ValidateOptions()); } -TEST_F(DumpstateTest, ValidateOptionsRemoteMode) { - ds.options_.is_remote_mode = true; - EXPECT_FALSE(ds.ValidateOptions()); +TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) { + options_.is_remote_mode = true; + EXPECT_FALSE(options_.ValidateOptions()); - ds.options_.do_broadcast = true; - ds.options_.do_zip_file = true; - ds.options_.do_add_date = true; - ds.options_.use_outfile = "a/b/c"; // do_broadcast needs outfile - EXPECT_TRUE(ds.ValidateOptions()); + options_.do_broadcast = true; + options_.do_zip_file = true; + options_.do_add_date = true; + options_.use_outfile = "a/b/c"; // do_broadcast needs outfile + EXPECT_TRUE(options_.ValidateOptions()); } +class DumpstateTest : public DumpstateBaseTest { + public: + void SetUp() { + DumpstateBaseTest::SetUp(); + SetDryRun(false); + SetBuildType(android::base::GetProperty("ro.build.type", "(unknown)")); + ds.progress_.reset(new Progress()); + ds.update_progress_threshold_ = 0; + ds.options_.reset(new Dumpstate::DumpOptions()); + } + + // Runs a command and capture `stdout` and `stderr`. + int RunCommand(const std::string& title, const std::vector<std::string>& full_command, + const CommandOptions& options = CommandOptions::DEFAULT) { + CaptureStdout(); + CaptureStderr(); + int status = ds.RunCommand(title, full_command, options); + out = GetCapturedStdout(); + err = GetCapturedStderr(); + return status; + } + + // Dumps a file and capture `stdout` and `stderr`. + int DumpFile(const std::string& title, const std::string& path) { + CaptureStdout(); + CaptureStderr(); + int status = ds.DumpFile(title, path); + out = GetCapturedStdout(); + err = GetCapturedStderr(); + return status; + } + + void SetProgress(long progress, long initial_max, long threshold = 0) { + ds.options_->do_progress_updates = true; + ds.update_progress_threshold_ = threshold; + ds.last_updated_progress_ = 0; + ds.progress_.reset(new Progress(initial_max, progress, 1.2)); + } + + std::string GetProgressMessage(const std::string& listener_name, int progress, int max, + int old_max = 0, bool update_progress = true) { + EXPECT_EQ(progress, ds.progress_->Get()) << "invalid progress"; + EXPECT_EQ(max, ds.progress_->GetMax()) << "invalid max"; + + bool max_increased = old_max > 0; + + std::string message = ""; + if (max_increased) { + message = + android::base::StringPrintf("Adjusting max progress from %d to %d\n", old_max, max); + } + + if (update_progress) { + message += android::base::StringPrintf("Setting progress (%s): %d/%d\n", + listener_name.c_str(), progress, max); + } + + return message; + } + + // `stdout` and `stderr` from the last command ran. + std::string out, err; + + Dumpstate& ds = Dumpstate::GetInstance(); +}; + TEST_F(DumpstateTest, RunCommandNoArgs) { EXPECT_EQ(-1, RunCommand("", {})); } @@ -633,6 +655,32 @@ TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild) { EXPECT_THAT(err, StrEq("stderr\n")); } +TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild_withUnroot) { + if (!IsStandalone()) { + // TODO: temporarily disabled because it might cause other tests to fail after dropping + // to Shell - need to refactor tests to avoid this problem) + MYLOGE( + "Skipping DumpstateTest.RunCommandAsRootNonUserBuild_withUnroot() " + "on test suite\n") + return; + } + if (PropertiesHelper::IsUserBuild()) { + ALOGI("Skipping RunCommandAsRootNonUserBuild_withUnroot on user builds\n"); + return; + } + + // Same test as above, but with unroot property set, which will override su availability. + SetUnroot(true); + DropRoot(); + + EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"}, + CommandOptions::WithTimeout(1).AsRoot().Build())); + + // AsRoot is ineffective. + EXPECT_THAT(out, StrEq("2000\nstdout\n")); + EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n")); +} + TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnUserBuild) { if (!IsStandalone()) { // TODO: temporarily disabled because it might cause other tests to fail after dropping @@ -675,6 +723,32 @@ TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild) { EXPECT_THAT(err, StrEq("stderr\n")); } +TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild_withUnroot) { + if (!IsStandalone()) { + // TODO: temporarily disabled because it might cause other tests to fail after dropping + // to Shell - need to refactor tests to avoid this problem) + MYLOGE( + "Skipping DumpstateTest.RunCommandAsRootIfAvailableOnDebugBuild_withUnroot() " + "on test suite\n") + return; + } + if (PropertiesHelper::IsUserBuild()) { + ALOGI("Skipping RunCommandAsRootIfAvailableOnDebugBuild_withUnroot on user builds\n"); + return; + } + // Same test as above, but with unroot property set, which will override su availability. + SetUnroot(true); + + DropRoot(); + + EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"}, + CommandOptions::WithTimeout(1).AsRootIfAvailable().Build())); + + // It's a userdebug build, so "su root" should be available, but unroot=true overrides it. + EXPECT_THAT(out, StrEq("2000\nstdout\n")); + EXPECT_THAT(err, StrEq("stderr\n")); +} + TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) { EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist")); EXPECT_THAT(out, diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp index 77f09b7459..6cbb691676 100644 --- a/cmds/dumpstate/utils.cpp +++ b/cmds/dumpstate/utils.cpp @@ -82,8 +82,12 @@ static const long STATS_MAX_AVERAGE = 100000; CommandOptions Dumpstate::DEFAULT_DUMPSYS = CommandOptions::WithTimeout(30).Build(); +// TODO(111441001): Default DumpOptions to sensible values. Dumpstate::Dumpstate(const std::string& version) - : pid_(getpid()), version_(version), now_(time(nullptr)) { + : pid_(getpid()), + options_(new Dumpstate::DumpOptions()), + version_(version), + now_(time(nullptr)) { } Dumpstate& Dumpstate::GetInstance() { @@ -916,7 +920,7 @@ void Dumpstate::UpdateProgress(int32_t delta_sec) { bool max_changed = progress_->Inc(delta_sec); // ...but only notifiy listeners when necessary. - if (!update_progress_) return; + if (!options_->do_progress_updates) return; int progress = progress_->Get(); int max = progress_->GetMax(); diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp index 9d0d8ba8b7..2e9701f8b0 100644 --- a/cmds/installd/Android.bp +++ b/cmds/installd/Android.bp @@ -14,6 +14,7 @@ cc_defaults { "CacheItem.cpp", "CacheTracker.cpp", "InstalldNativeService.cpp", + "QuotaUtils.cpp", "dexopt.cpp", "globals.cpp", "utils.cpp", @@ -33,6 +34,21 @@ cc_defaults { "libutils", ], + product_variables: { + arc: { + exclude_srcs: [ + "QuotaUtils.cpp", + ], + static_libs: [ + "libarcdiskquota", + "arc_services_aidl", + ], + cflags: [ + "-DUSE_ARC", + ], + }, + }, + clang: true, tidy: true, @@ -59,6 +75,26 @@ cc_library_static { aidl: { export_aidl_headers: true, }, + + product_variables: { + arc: { + exclude_srcs: [ + "QuotaUtils.cpp", + ], + static_libs: [ + "libarcdiskquota", + "arc_services_aidl", + ], + cflags: [ + "-DUSE_ARC", + ], + }, + }, +} + +cc_library_headers { + name: "libinstalld_headers", + export_include_dirs: ["."], } // @@ -73,6 +109,21 @@ cc_binary { static_libs: ["libdiskusage"], init_rc: ["installd.rc"], + + product_variables: { + arc: { + exclude_srcs: [ + "QuotaUtils.cpp", + ], + static_libs: [ + "libarcdiskquota", + "arc_services_aidl", + ], + cflags: [ + "-DUSE_ARC", + ], + }, + }, } // OTA chroot tool diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp index 515f915b8b..e29ff4c248 100644 --- a/cmds/installd/CacheItem.cpp +++ b/cmds/installd/CacheItem.cpp @@ -73,7 +73,7 @@ int CacheItem::purge() { FTS *fts; FTSENT *p; char *argv[] = { (char*) path.c_str(), nullptr }; - if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) { + if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) { PLOG(WARNING) << "Failed to fts_open " << path; return -1; } diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp index ea0cd9e4e2..8b868fb584 100644 --- a/cmds/installd/CacheTracker.cpp +++ b/cmds/installd/CacheTracker.cpp @@ -19,13 +19,13 @@ #include "CacheTracker.h" #include <fts.h> -#include <sys/quota.h> #include <sys/xattr.h> #include <utils/Trace.h> #include <android-base/logging.h> #include <android-base/stringprintf.h> +#include "QuotaUtils.h" #include "utils.h" using android::base::StringPrintf; @@ -33,9 +33,13 @@ using android::base::StringPrintf; namespace android { namespace installd { -CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice) : - cacheUsed(0), cacheQuota(0), mUserId(userId), mAppId(appId), mQuotaDevice(quotaDevice), - mItemsLoaded(false) { +CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& uuid) + : cacheUsed(0), + cacheQuota(0), + mUserId(userId), + mAppId(appId), + mItemsLoaded(false), + mUuid(uuid) { } CacheTracker::~CacheTracker() { @@ -72,26 +76,18 @@ void CacheTracker::loadStats() { bool CacheTracker::loadQuotaStats() { int cacheGid = multiuser_get_cache_gid(mUserId, mAppId); int extCacheGid = multiuser_get_ext_cache_gid(mUserId, mAppId); - if (!mQuotaDevice.empty() && cacheGid != -1 && extCacheGid != -1) { - struct dqblk dq; - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid; - } - return false; + if (IsQuotaSupported(mUuid) && cacheGid != -1 && extCacheGid != -1) { + int64_t space; + if ((space = GetOccupiedSpaceForGid(mUuid, cacheGid)) != -1) { + cacheUsed += space; } else { - cacheUsed += dq.dqb_curspace; + return false; } - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), extCacheGid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid; - } - return false; + if ((space = GetOccupiedSpaceForGid(mUuid, extCacheGid)) != -1) { + cacheUsed += space; } else { - cacheUsed += dq.dqb_curspace; + return false; } return true; } else { @@ -103,7 +99,7 @@ void CacheTracker::loadItemsFrom(const std::string& path) { FTS *fts; FTSENT *p; char *argv[] = { (char*) path.c_str(), nullptr }; - if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) { + if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) { PLOG(WARNING) << "Failed to fts_open " << path; return; } diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h index 44359b4970..b0527e7b3f 100644 --- a/cmds/installd/CacheTracker.h +++ b/cmds/installd/CacheTracker.h @@ -39,7 +39,7 @@ namespace installd { */ class CacheTracker { public: - CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice); + CacheTracker(userid_t userId, appid_t appId, const std::string& uuid); ~CacheTracker(); std::string toString(); @@ -61,8 +61,8 @@ public: private: userid_t mUserId; appid_t mAppId; - std::string mQuotaDevice; bool mItemsLoaded; + const std::string& mUuid; std::vector<std::string> mDataPaths; diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index e336232aed..2439dff54e 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -31,7 +31,6 @@ #include <sys/file.h> #include <sys/ioctl.h> #include <sys/mman.h> -#include <sys/quota.h> #include <sys/resource.h> #include <sys/stat.h> #include <sys/statvfs.h> @@ -64,6 +63,7 @@ #include "CacheTracker.h" #include "MatchExtensionGen.h" +#include "QuotaUtils.h" #ifndef LOG_TAG #define LOG_TAG "installd" @@ -77,7 +77,6 @@ namespace installd { static constexpr const char* kCpPath = "/system/bin/cp"; static constexpr const char* kXattrDefault = "user.default"; -static constexpr const char* kPropHasReserved = "vold.has_reserved"; static constexpr const int MIN_RESTRICTED_HOME_SDK_VERSION = 24; // > M @@ -267,11 +266,6 @@ status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */ for (const auto& n : mStorageMounts) { out << " " << n.first << " = " << n.second << endl; } - - out << endl << "Quota reverse mounts:" << endl; - for (const auto& n : mQuotaReverseMounts) { - out << " " << n.first << " = " << n.second << endl; - } } { @@ -352,55 +346,6 @@ static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t ui return 0; } -/** - * Ensure that we have a hard-limit quota to protect against abusive apps; - * they should never use more than 90% of blocks or 50% of inodes. - */ -static int prepare_app_quota(const std::unique_ptr<std::string>& uuid ATTRIBUTE_UNUSED, - const std::string& device, uid_t uid) { - // Skip when reserved blocks are protecting us against abusive apps - if (android::base::GetBoolProperty(kPropHasReserved, false)) return 0; - // Skip when device no quotas present - if (device.empty()) return 0; - - struct dqblk dq; - if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, - reinterpret_cast<char*>(&dq)) != 0) { - PLOG(WARNING) << "Failed to find quota for " << uid; - return -1; - } - -#if APPLY_HARD_QUOTAS - if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) { - auto path = create_data_path(uuid ? uuid->c_str() : nullptr); - struct statvfs stat; - if (statvfs(path.c_str(), &stat) != 0) { - PLOG(WARNING) << "Failed to statvfs " << path; - return -1; - } - - dq.dqb_valid = QIF_LIMITS; - dq.dqb_bhardlimit = - (((static_cast<uint64_t>(stat.f_blocks) * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE; - dq.dqb_ihardlimit = (stat.f_files / 2); - if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid, - reinterpret_cast<char*>(&dq)) != 0) { - PLOG(WARNING) << "Failed to set hard quota for " << uid; - return -1; - } else { - LOG(DEBUG) << "Applied hard quotas for " << uid; - return 0; - } - } else { - // Hard quota already set; assume it's reasonable - return 0; - } -#else - // Hard quotas disabled - return 0; -#endif -} - static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) { if (!property_get_bool("dalvik.vm.usejitprofiles", false)) { return true; @@ -515,10 +460,6 @@ binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::s return error("Failed to restorecon " + path); } - if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) { - return error("Failed to set hard quota " + path); - } - if (!prepare_app_profile_dir(packageName, appId, userId)) { return error("Failed to prepare profiles for " + packageName); } @@ -715,7 +656,7 @@ binder::Status InstalldNativeService::fixupAppData(const std::unique_ptr<std::st auto ce_path = create_data_user_ce_path(uuid_, user); auto de_path = create_data_user_de_path(uuid_, user); char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(), nullptr }; - if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) { + if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) { return error("Failed to fts_open"); } while ((p = fts_read(fts)) != nullptr) { @@ -840,7 +781,7 @@ binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std: }; LOG(DEBUG) << "Copying " << from << " to " << to; - int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true); + int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true); if (rc != 0) { res = error(rc, "Failed copying " + from + " to " + to); goto fail; @@ -886,7 +827,7 @@ binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std: argv[7] = (char*) to.c_str(); LOG(DEBUG) << "Copying " << from << " to " << to; - int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true); + int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true); if (rc != 0) { res = error(rc, "Failed copying " + from + " to " + to); goto fail; @@ -899,7 +840,7 @@ binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std: argv[7] = (char*) to.c_str(); LOG(DEBUG) << "Copying " << from << " to " << to; - int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true); + int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true); if (rc != 0) { res = error(rc, "Failed copying " + from + " to " + to); goto fail; @@ -922,20 +863,20 @@ fail: // Nuke everything we might have already copied { auto to = create_data_app_package_path(to_uuid, data_app_name); - if (delete_dir_contents(to.c_str(), 1, NULL) != 0) { + if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) { LOG(WARNING) << "Failed to rollback " << to; } } for (auto user : users) { { auto to = create_data_user_de_package_path(to_uuid, user, package_name); - if (delete_dir_contents(to.c_str(), 1, NULL) != 0) { + if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) { LOG(WARNING) << "Failed to rollback " << to; } } { auto to = create_data_user_ce_package_path(to_uuid, user, package_name); - if (delete_dir_contents(to.c_str(), 1, NULL) != 0) { + if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) { LOG(WARNING) << "Failed to rollback " << to; } } @@ -958,13 +899,6 @@ binder::Status InstalldNativeService::createUserData(const std::unique_ptr<std:: } } - // Data under /data/media doesn't have an app, but we still want - // to limit it to prevent abuse. - if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), - multiuser_get_uid(userId, AID_MEDIA_RW))) { - return error("Failed to set hard quota for media_rw"); - } - return ok(); } @@ -1011,9 +945,9 @@ binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::strin CHECK_ARGUMENT_UUID(uuid); std::lock_guard<std::recursive_mutex> lock(mLock); + auto uuidString = uuid ? *uuid : ""; const char* uuid_ = uuid ? uuid->c_str() : nullptr; auto data_path = create_data_path(uuid_); - auto device = findQuotaDeviceForUuid(uuid); auto noop = (flags & FLAG_FREE_CACHE_NOOP); int64_t free = data_disk_free(data_path); @@ -1045,10 +979,10 @@ binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::strin auto media_path = findDataMediaPath(uuid, user) + "/Android/data/"; char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(), (char*) media_path.c_str(), nullptr }; - if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) { + if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) { return error("Failed to fts_open"); } - while ((p = fts_read(fts)) != NULL) { + while ((p = fts_read(fts)) != nullptr) { if (p->fts_info == FTS_D && p->fts_level == 1) { uid_t uid = p->fts_statp->st_uid; if (multiuser_get_app_id(uid) == AID_MEDIA_RW) { @@ -1060,7 +994,7 @@ binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::strin search->second->addDataPath(p->fts_path); } else { auto tracker = std::shared_ptr<CacheTracker>(new CacheTracker( - multiuser_get_user_id(uid), multiuser_get_app_id(uid), device)); + multiuser_get_user_id(uid), multiuser_get_app_id(uid), uuidString)); tracker->addDataPath(p->fts_path); { std::lock_guard<std::recursive_mutex> lock(mQuotasLock); @@ -1225,53 +1159,26 @@ static std::string toString(std::vector<int64_t> values) { } #endif -static void collectQuotaStats(const std::string& device, int32_t userId, +static void collectQuotaStats(const std::string& uuid, int32_t userId, int32_t appId, struct stats* stats, struct stats* extStats) { - if (device.empty()) return; - - struct dqblk dq; - + int64_t space; if (stats != nullptr) { uid_t uid = multiuser_get_uid(userId, appId); - if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid; - } - } else { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace; -#endif - stats->dataSize += dq.dqb_curspace; + if ((space = GetOccupiedSpaceForUid(uuid, uid)) != -1) { + stats->dataSize += space; } int cacheGid = multiuser_get_cache_gid(userId, appId); if (cacheGid != -1) { - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), cacheGid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << cacheGid; - } - } else { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace; -#endif - stats->cacheSize += dq.dqb_curspace; + if ((space = GetOccupiedSpaceForGid(uuid, cacheGid)) != -1) { + stats->cacheSize += space; } } int sharedGid = multiuser_get_shared_gid(0, appId); if (sharedGid != -1) { - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << sharedGid; - } - } else { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace; -#endif - stats->codeSize += dq.dqb_curspace; + if ((space = GetOccupiedSpaceForGid(uuid, sharedGid)) != -1) { + stats->codeSize += space; } } } @@ -1279,32 +1186,16 @@ static void collectQuotaStats(const std::string& device, int32_t userId, if (extStats != nullptr) { int extGid = multiuser_get_ext_gid(userId, appId); if (extGid != -1) { - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extGid; - } - } else { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for GID " << extGid << " " << dq.dqb_curspace; -#endif - extStats->dataSize += dq.dqb_curspace; + if ((space = GetOccupiedSpaceForGid(uuid, extGid)) != -1) { + extStats->dataSize += space; } } int extCacheGid = multiuser_get_ext_cache_gid(userId, appId); if (extCacheGid != -1) { - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extCacheGid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extCacheGid; - } - } else { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for GID " << extCacheGid << " " << dq.dqb_curspace; -#endif - extStats->dataSize += dq.dqb_curspace; - extStats->cacheSize += dq.dqb_curspace; + if ((space = GetOccupiedSpaceForGid(uuid, extCacheGid)) != -1) { + extStats->dataSize += space; + extStats->cacheSize += space; } } } @@ -1398,11 +1289,11 @@ static void collectManualExternalStatsForUser(const std::string& path, struct st FTS *fts; FTSENT *p; char *argv[] = { (char*) path.c_str(), nullptr }; - if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) { + if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) { PLOG(ERROR) << "Failed to fts_open " << path; return; } - while ((p = fts_read(fts)) != NULL) { + while ((p = fts_read(fts)) != nullptr) { p->fts_number = p->fts_parent->fts_number; switch (p->fts_info) { case FTS_D: @@ -1468,10 +1359,10 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri memset(&stats, 0, sizeof(stats)); memset(&extStats, 0, sizeof(extStats)); + auto uuidString = uuid ? *uuid : ""; const char* uuid_ = uuid ? uuid->c_str() : nullptr; - auto device = findQuotaDeviceForUuid(uuid); - if (device.empty()) { + if (!IsQuotaSupported(uuidString)) { flags &= ~FLAG_USE_QUOTA; } @@ -1491,7 +1382,7 @@ binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::stri ATRACE_END(); ATRACE_BEGIN("quota"); - collectQuotaStats(device, userId, appId, &stats, &extStats); + collectQuotaStats(uuidString, userId, appId, &stats, &extStats); ATRACE_END(); } else { ATRACE_BEGIN("code"); @@ -1574,27 +1465,19 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str memset(&stats, 0, sizeof(stats)); memset(&extStats, 0, sizeof(extStats)); + auto uuidString = uuid ? *uuid : ""; const char* uuid_ = uuid ? uuid->c_str() : nullptr; - auto device = findQuotaDeviceForUuid(uuid); - if (device.empty()) { + if (!IsQuotaSupported(uuidString)) { flags &= ~FLAG_USE_QUOTA; } if (flags & FLAG_USE_QUOTA) { - struct dqblk dq; + int64_t space; ATRACE_BEGIN("obb"); - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << AID_MEDIA_OBB; - } - } else { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace; -#endif - extStats.codeSize += dq.dqb_curspace; + if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) { + extStats.codeSize += space; } ATRACE_END(); @@ -1620,16 +1503,8 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str ATRACE_BEGIN("external"); uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW); - if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid; - } - } else { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace; -#endif - extStats.dataSize += dq.dqb_curspace; + if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) { + extStats.dataSize += space; } ATRACE_END(); @@ -1646,7 +1521,7 @@ binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::str int64_t dataSize = extStats.dataSize; for (auto appId : appIds) { if (appId >= AID_APP_START) { - collectQuotaStats(device, userId, appId, &stats, &extStats); + collectQuotaStats(uuidString, userId, appId, &stats, &extStats); #if MEASURE_DEBUG // Sleep to make sure we don't lose logs @@ -1728,6 +1603,7 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std: LOG(INFO) << "Measuring external " << userId; #endif + auto uuidString = uuid ? *uuid : ""; const char* uuid_ = uuid ? uuid->c_str() : nullptr; int64_t totalSize = 0; @@ -1737,58 +1613,33 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std: int64_t appSize = 0; int64_t obbSize = 0; - auto device = findQuotaDeviceForUuid(uuid); - if (device.empty()) { + if (!IsQuotaSupported(uuidString)) { flags &= ~FLAG_USE_QUOTA; } if (flags & FLAG_USE_QUOTA) { - struct dqblk dq; + int64_t space; ATRACE_BEGIN("quota"); uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW); - if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, - reinterpret_cast<char*>(&dq)) != 0) { - if (errno != ESRCH) { - PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid; - } - } else { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace; -#endif - totalSize = dq.dqb_curspace; + if ((space = GetOccupiedSpaceForUid(uuidString, uid)) != -1) { + totalSize = space; } gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO); - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), audioGid, - reinterpret_cast<char*>(&dq)) == 0) { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for GID " << audioGid << " " << dq.dqb_curspace; -#endif - audioSize = dq.dqb_curspace; + if ((space = GetOccupiedSpaceForGid(uuidString, audioGid)) != -1) { + audioSize = space; } gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO); - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), videoGid, - reinterpret_cast<char*>(&dq)) == 0) { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for GID " << videoGid << " " << dq.dqb_curspace; -#endif - videoSize = dq.dqb_curspace; + if ((space = GetOccupiedSpaceForGid(uuidString, videoGid)) != -1) { + videoSize = space; } gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE); - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), imageGid, - reinterpret_cast<char*>(&dq)) == 0) { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for GID " << imageGid << " " << dq.dqb_curspace; -#endif - imageSize = dq.dqb_curspace; + if ((space = GetOccupiedSpaceForGid(uuidString, imageGid)) != -1) { + imageSize = space; } - if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB, - reinterpret_cast<char*>(&dq)) == 0) { -#if MEASURE_DEBUG - LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace; -#endif - obbSize = dq.dqb_curspace; + if ((space = GetOccupiedSpaceForGid(uuidString, AID_MEDIA_OBB)) != -1) { + obbSize = space; } ATRACE_END(); @@ -1797,7 +1648,7 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std: memset(&extStats, 0, sizeof(extStats)); for (auto appId : appIds) { if (appId >= AID_APP_START) { - collectQuotaStats(device, userId, appId, nullptr, &extStats); + collectQuotaStats(uuidString, userId, appId, nullptr, &extStats); } } appSize = extStats.dataSize; @@ -1808,10 +1659,10 @@ binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std: FTSENT *p; auto path = create_data_media_path(uuid_, userId); char *argv[] = { (char*) path.c_str(), nullptr }; - if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) { + if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) { return error("Failed to fts_open " + path); } - while ((p = fts_read(fts)) != NULL) { + while ((p = fts_read(fts)) != nullptr) { char* ext; int64_t size = (p->fts_statp->st_blocks * 512); switch (p->fts_info) { @@ -2041,7 +1892,7 @@ binder::Status InstalldNativeService::linkNativeLibraryDirectory( } } else { if (S_ISDIR(libStat.st_mode)) { - if (delete_dir_contents(libsymlink, 1, NULL) < 0) { + if (delete_dir_contents(libsymlink, 1, nullptr) < 0) { res = error("Failed to delete " + _libsymlink); goto out; } @@ -2083,14 +1934,14 @@ out: static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd) { execl(kIdMapPath, kIdMapPath, "--fd", target_apk, overlay_apk, - StringPrintf("%d", idmap_fd).c_str(), (char*)NULL); + StringPrintf("%d", idmap_fd).c_str(), (char*)nullptr); PLOG(ERROR) << "execl (" << kIdMapPath << ") failed"; } static void run_verify_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd) { execl(kIdMapPath, kIdMapPath, "--verify", target_apk, overlay_apk, - StringPrintf("%d", idmap_fd).c_str(), (char*)NULL); + StringPrintf("%d", idmap_fd).c_str(), (char*)nullptr); PLOG(ERROR) << "execl (" << kIdMapPath << ") failed"; } @@ -2141,7 +1992,7 @@ static bool delete_stale_idmap(const char* target_apk, const char* overlay_apk, static int flatten_path(const char *prefix, const char *suffix, const char *overlay_path, char *idmap_path, size_t N) { - if (overlay_path == NULL || idmap_path == NULL) { + if (overlay_path == nullptr || idmap_path == nullptr) { return -1; } const size_t len_overlay_path = strlen(overlay_path); @@ -2482,7 +2333,7 @@ binder::Status InstalldNativeService::installApkVerity(const std::string& filePa std::to_string(shmSize)); } auto data = std::unique_ptr<void, std::function<void (void *)>>( - mmap(NULL, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0), + mmap(nullptr, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0), [contentSize] (void* ptr) { if (ptr != MAP_FAILED) { munmap(ptr, contentSize); @@ -2585,7 +2436,12 @@ binder::Status InstalldNativeService::invalidateMounts() { std::lock_guard<std::recursive_mutex> lock(mMountsLock); mStorageMounts.clear(); - mQuotaReverseMounts.clear(); + +#if !BYPASS_QUOTA + if (!InvalidateQuotaMounts()) { + return error("Failed to read mounts"); + } +#endif std::ifstream in("/proc/mounts"); if (!in.is_open()) { @@ -2606,32 +2462,6 @@ binder::Status InstalldNativeService::invalidateMounts() { mStorageMounts[source] = target; } #endif - -#if !BYPASS_QUOTA - if (source.compare(0, 11, "/dev/block/") == 0) { - struct dqblk dq; - if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0, - reinterpret_cast<char*>(&dq)) == 0) { - LOG(DEBUG) << "Found quota mount " << source << " at " << target; - mQuotaReverseMounts[target] = source; - - // ext4 only enables DQUOT_USAGE_ENABLED by default, so we - // need to kick it again to enable DQUOT_LIMITS_ENABLED. We - // only need hard limits enabled when we're not being protected - // by reserved blocks. - if (!android::base::GetBoolProperty(kPropHasReserved, false)) { - if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1, - nullptr) != 0 && errno != EBUSY) { - PLOG(ERROR) << "Failed to enable USRQUOTA on " << source; - } - if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1, - nullptr) != 0 && errno != EBUSY) { - PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source; - } - } - } - } -#endif } return ok(); } @@ -2649,16 +2479,10 @@ std::string InstalldNativeService::findDataMediaPath( return StringPrintf("%s/%u", resolved.c_str(), userid); } -std::string InstalldNativeService::findQuotaDeviceForUuid( - const std::unique_ptr<std::string>& uuid) { - std::lock_guard<std::recursive_mutex> lock(mMountsLock); - auto path = create_data_path(uuid ? uuid->c_str() : nullptr); - return mQuotaReverseMounts[path]; -} - binder::Status InstalldNativeService::isQuotaSupported( - const std::unique_ptr<std::string>& volumeUuid, bool* _aidl_return) { - *_aidl_return = !findQuotaDeviceForUuid(volumeUuid).empty(); + const std::unique_ptr<std::string>& uuid, bool* _aidl_return) { + auto uuidString = uuid ? *uuid : ""; + *_aidl_return = IsQuotaSupported(uuidString); return ok(); } diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index cebd3f90d3..367f2c1547 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -150,14 +150,11 @@ private: /* Map of all storage mounts from source to target */ std::unordered_map<std::string, std::string> mStorageMounts; - /* Map of all quota mounts from target to source */ - std::unordered_map<std::string, std::string> mQuotaReverseMounts; /* Map from UID to cache quota size */ std::unordered_map<uid_t, int64_t> mCacheQuotas; std::string findDataMediaPath(const std::unique_ptr<std::string>& uuid, userid_t userid); - std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid); }; } // namespace installd diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS index 50440f1dae..5d4f176a24 100644 --- a/cmds/installd/OWNERS +++ b/cmds/installd/OWNERS @@ -1,7 +1,8 @@ set noparent -calin@google.com agampe@google.com +calin@google.com jsharkey@android.com -toddke@google.com +mathieuc@google.com ngeoffray@google.com +toddke@google.com diff --git a/cmds/installd/QuotaUtils.cpp b/cmds/installd/QuotaUtils.cpp new file mode 100644 index 0000000000..b238dd36e3 --- /dev/null +++ b/cmds/installd/QuotaUtils.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2018 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. + */ + +#include "QuotaUtils.h" + +#include <fstream> +#include <unordered_map> + +#include <sys/quota.h> + +#include <android-base/logging.h> + +#include "utils.h" + +namespace android { +namespace installd { + +namespace { + +std::recursive_mutex mMountsLock; + +/* Map of all quota mounts from target to source */ +std::unordered_map<std::string, std::string> mQuotaReverseMounts; + +std::string& FindQuotaDeviceForUuid(const std::string& uuid) { + std::lock_guard<std::recursive_mutex> lock(mMountsLock); + auto path = create_data_path(uuid.empty() ? nullptr : uuid.c_str()); + return mQuotaReverseMounts[path]; +} + +} // namespace + +bool InvalidateQuotaMounts() { + std::lock_guard<std::recursive_mutex> lock(mMountsLock); + + mQuotaReverseMounts.clear(); + + std::ifstream in("/proc/mounts"); + if (!in.is_open()) { + return false; + } + + std::string source; + std::string target; + std::string ignored; + while (!in.eof()) { + std::getline(in, source, ' '); + std::getline(in, target, ' '); + std::getline(in, ignored); + + if (source.compare(0, 11, "/dev/block/") == 0) { + struct dqblk dq; + if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0, + reinterpret_cast<char*>(&dq)) == 0) { + LOG(DEBUG) << "Found quota mount " << source << " at " << target; + mQuotaReverseMounts[target] = source; + } + } + } + return true; +} + +bool IsQuotaSupported(const std::string& uuid) { + return !FindQuotaDeviceForUuid(uuid).empty(); +} + +int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid) { + const std::string device = FindQuotaDeviceForUuid(uuid); + if (device == "") { + return -1; + } + struct dqblk dq; + if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid, + reinterpret_cast<char*>(&dq)) != 0) { + if (errno != ESRCH) { + PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid; + } + return -1; + } else { +#if MEASURE_DEBUG + LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace; +#endif + return dq.dqb_curspace; + } +} + +int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid) { + const std::string device = FindQuotaDeviceForUuid(uuid); + if (device == "") { + return -1; + } + struct dqblk dq; + if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), gid, + reinterpret_cast<char*>(&dq)) != 0) { + if (errno != ESRCH) { + PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << gid; + } + return -1; + } else { +#if MEASURE_DEBUG + LOG(DEBUG) << "quotactl() for GID " << gid << " " << dq.dqb_curspace; +#endif + return dq.dqb_curspace; + } + +} + +} // namespace installd +} // namespace android diff --git a/cmds/installd/QuotaUtils.h b/cmds/installd/QuotaUtils.h new file mode 100644 index 0000000000..9ad170fcbb --- /dev/null +++ b/cmds/installd/QuotaUtils.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef ANDROID_INSTALLD_QUOTA_UTILS_H_ +#define ANDROID_INSTALLD_QUOTA_UTILS_H_ + +#include <memory> +#include <string> + +namespace android { +namespace installd { + +/* Clear and recompute the reverse mounts map */ +bool InvalidateQuotaMounts(); + +/* Whether quota is supported in the device with the given uuid */ +bool IsQuotaSupported(const std::string& uuid); + +/* Get the current occupied space in bytes for a uid or -1 if fails */ +int64_t GetOccupiedSpaceForUid(const std::string& uuid, uid_t uid); + +/* Get the current occupied space in bytes for a gid or -1 if fails */ +int64_t GetOccupiedSpaceForGid(const std::string& uuid, gid_t gid); + +} // namespace installd +} // namespace android + +#endif // ANDROID_INSTALLD_QUOTA_UTILS_H_ diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 03a411d849..aad9939bc5 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -54,6 +54,8 @@ #include "utils.h" using android::base::EndsWith; +using android::base::GetBoolProperty; +using android::base::GetProperty; using android::base::ReadFully; using android::base::StringPrintf; using android::base::WriteFully; @@ -181,42 +183,17 @@ bool clear_primary_current_profile(const std::string& package_name, const std::s return clear_current_profile(package_name, location, user, /*is_secondary_dex*/false); } -static int split_count(const char *str) -{ - char *ctx; - int count = 0; - char buf[kPropertyValueMax]; - - strlcpy(buf, str, sizeof(buf)); - char *pBuf = buf; - - while(strtok_r(pBuf, " ", &ctx) != NULL) { - count++; - pBuf = NULL; - } - - return count; -} - -static int split(char *buf, const char **argv) -{ - char *ctx; - int count = 0; - char *tok; - char *pBuf = buf; - - while((tok = strtok_r(pBuf, " ", &ctx)) != NULL) { - argv[count++] = tok; - pBuf = NULL; - } - - return count; +static std::vector<std::string> SplitBySpaces(const std::string& str) { + if (str.empty()) { + return {}; + } + return android::base::Split(str, " "); } static const char* get_location_from_path(const char* path) { static constexpr char kLocationSeparator = '/'; const char *location = strrchr(path, kLocationSeparator); - if (location == NULL) { + if (location == nullptr) { return path; } else { // Skip the separator character. @@ -224,341 +201,279 @@ static const char* get_location_from_path(const char* path) { } } -[[ noreturn ]] -static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd, - const char* input_file_name, const char* output_file_name, int swap_fd, - const char* instruction_set, const char* compiler_filter, - bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd, - const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks, - bool generate_compact_dex, int dex_metadata_fd, const char* compilation_reason) { - static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; - - if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) { - LOG(ERROR) << "Instruction set '" << instruction_set << "' longer than max length of " - << MAX_INSTRUCTION_SET_LEN; - exit(DexoptReturnCodes::kInstructionSetLength); - } - - // Get the relative path to the input file. - const char* relative_input_file_name = get_location_from_path(input_file_name); - - char dex2oat_Xms_flag[kPropertyValueMax]; - bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0; - - char dex2oat_Xmx_flag[kPropertyValueMax]; - bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, NULL) > 0; - - char dex2oat_threads_buf[kPropertyValueMax]; - bool have_dex2oat_threads_flag = get_property(post_bootcomplete - ? "dalvik.vm.dex2oat-threads" - : "dalvik.vm.boot-dex2oat-threads", - dex2oat_threads_buf, - NULL) > 0; - char dex2oat_threads_arg[kPropertyValueMax + 2]; - if (have_dex2oat_threads_flag) { - sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf); - } - - char dex2oat_isa_features_key[kPropertyKeyMax]; - sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set); - char dex2oat_isa_features[kPropertyValueMax]; - bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key, - dex2oat_isa_features, NULL) > 0; - - char dex2oat_isa_variant_key[kPropertyKeyMax]; - sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set); - char dex2oat_isa_variant[kPropertyValueMax]; - bool have_dex2oat_isa_variant = get_property(dex2oat_isa_variant_key, - dex2oat_isa_variant, NULL) > 0; - - const char *dex2oat_norelocation = "-Xnorelocate"; - bool have_dex2oat_relocation_skip_flag = false; - - char dex2oat_flags[kPropertyValueMax]; - int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags", - dex2oat_flags, NULL) <= 0 ? 0 : split_count(dex2oat_flags); - ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags); - - // If we are booting without the real /data, don't spend time compiling. - char vold_decrypt[kPropertyValueMax]; - bool have_vold_decrypt = get_property("vold.decrypt", vold_decrypt, "") > 0; - bool skip_compilation = (have_vold_decrypt && - (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 || - (strcmp(vold_decrypt, "1") == 0))); - - bool generate_debug_info = property_get_bool("debug.generate-debug-info", false); - - char app_image_format[kPropertyValueMax]; - char image_format_arg[strlen("--image-format=") + kPropertyValueMax]; - bool have_app_image_format = - image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0; - if (have_app_image_format) { - sprintf(image_format_arg, "--image-format=%s", app_image_format); - } - - char dex2oat_large_app_threshold[kPropertyValueMax]; - bool have_dex2oat_large_app_threshold = - get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, NULL) > 0; - char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax]; - if (have_dex2oat_large_app_threshold) { - sprintf(dex2oat_large_app_threshold_arg, - "--very-large-app-threshold=%s", - dex2oat_large_app_threshold); - } - - // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat. - const char* dex2oat_bin = "/system/bin/dex2oat"; - constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd"; - // Do not use dex2oatd for release candidates (give dex2oat more soak time). - bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL"; - if (is_debug_runtime() || (background_job_compile && is_debuggable_build() && !is_release)) { - if (access(kDex2oatDebugPath, X_OK) == 0) { - dex2oat_bin = kDex2oatDebugPath; - } - } - - bool generate_minidebug_info = kEnableMinidebugInfo && - android::base::GetBoolProperty(kMinidebugInfoSystemProperty, - kMinidebugInfoSystemPropertyDefault); - - static const char* RUNTIME_ARG = "--runtime-arg"; - - static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig - - // clang FORTIFY doesn't let us use strlen in constant array bounds, so we - // use arraysize instead. - char zip_fd_arg[arraysize("--zip-fd=") + MAX_INT_LEN]; - char zip_location_arg[arraysize("--zip-location=") + PKG_PATH_MAX]; - char input_vdex_fd_arg[arraysize("--input-vdex-fd=") + MAX_INT_LEN]; - char output_vdex_fd_arg[arraysize("--output-vdex-fd=") + MAX_INT_LEN]; - char oat_fd_arg[arraysize("--oat-fd=") + MAX_INT_LEN]; - char oat_location_arg[arraysize("--oat-location=") + PKG_PATH_MAX]; - char instruction_set_arg[arraysize("--instruction-set=") + MAX_INSTRUCTION_SET_LEN]; - char instruction_set_variant_arg[arraysize("--instruction-set-variant=") + kPropertyValueMax]; - char instruction_set_features_arg[arraysize("--instruction-set-features=") + kPropertyValueMax]; - char dex2oat_Xms_arg[arraysize("-Xms") + kPropertyValueMax]; - char dex2oat_Xmx_arg[arraysize("-Xmx") + kPropertyValueMax]; - char dex2oat_compiler_filter_arg[arraysize("--compiler-filter=") + kPropertyValueMax]; - bool have_dex2oat_swap_fd = false; - char dex2oat_swap_fd[arraysize("--swap-fd=") + MAX_INT_LEN]; - bool have_dex2oat_image_fd = false; - char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN]; - size_t class_loader_context_size = arraysize("--class-loader-context=") + PKG_PATH_MAX; - char target_sdk_version_arg[arraysize("-Xtarget-sdk-version:") + MAX_INT_LEN]; - char class_loader_context_arg[class_loader_context_size]; - if (class_loader_context != nullptr) { - snprintf(class_loader_context_arg, class_loader_context_size, "--class-loader-context=%s", - class_loader_context); - } - - sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd); - sprintf(zip_location_arg, "--zip-location=%s", relative_input_file_name); - sprintf(input_vdex_fd_arg, "--input-vdex-fd=%d", input_vdex_fd); - sprintf(output_vdex_fd_arg, "--output-vdex-fd=%d", output_vdex_fd); - sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd); - sprintf(oat_location_arg, "--oat-location=%s", output_file_name); - sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set); - sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant); - sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features); - if (swap_fd >= 0) { - have_dex2oat_swap_fd = true; - sprintf(dex2oat_swap_fd, "--swap-fd=%d", swap_fd); - } - if (image_fd >= 0) { - have_dex2oat_image_fd = true; - sprintf(dex2oat_image_fd, "--app-image-fd=%d", image_fd); - } - - if (have_dex2oat_Xms_flag) { - sprintf(dex2oat_Xms_arg, "-Xms%s", dex2oat_Xms_flag); - } - if (have_dex2oat_Xmx_flag) { - sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag); - } - sprintf(target_sdk_version_arg, "-Xtarget-sdk-version:%d", target_sdk_version); - - // Compute compiler filter. - - bool have_dex2oat_compiler_filter_flag = false; - if (skip_compilation) { - strlcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract", - sizeof(dex2oat_compiler_filter_arg)); - have_dex2oat_compiler_filter_flag = true; - have_dex2oat_relocation_skip_flag = true; - } else if (compiler_filter != nullptr) { - if (strlen(compiler_filter) + strlen("--compiler-filter=") < - arraysize(dex2oat_compiler_filter_arg)) { - sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", compiler_filter); - have_dex2oat_compiler_filter_flag = true; - } else { - ALOGW("Compiler filter name '%s' is too large (max characters is %zu)", - compiler_filter, - kPropertyValueMax); - } - } - - if (!have_dex2oat_compiler_filter_flag) { - char dex2oat_compiler_filter_flag[kPropertyValueMax]; - have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter", - dex2oat_compiler_filter_flag, NULL) > 0; - if (have_dex2oat_compiler_filter_flag) { - sprintf(dex2oat_compiler_filter_arg, - "--compiler-filter=%s", - dex2oat_compiler_filter_flag); - } - } - - // Check whether all apps should be compiled debuggable. - if (!debuggable) { - char prop_buf[kPropertyValueMax]; - debuggable = - (get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) && - (prop_buf[0] == '1'); - } - char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN]; - if (profile_fd != -1) { - sprintf(profile_arg, "--profile-file-fd=%d", profile_fd); - } - - // Get the directory of the apk to pass as a base classpath directory. - char base_dir[arraysize("--classpath-dir=") + PKG_PATH_MAX]; - std::string apk_dir(input_file_name); - unsigned long dir_index = apk_dir.rfind('/'); - bool has_base_dir = dir_index != std::string::npos; - if (has_base_dir) { - apk_dir = apk_dir.substr(0, dir_index); - sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str()); - } - - std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd); - - std::string compilation_reason_arg = compilation_reason == nullptr - ? "" - : std::string("--compilation-reason=") + compilation_reason; - - ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name); - - // Disable cdex if update input vdex is true since this combination of options is not - // supported. - const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd); - - const char* argv[9 // program name, mandatory arguments and the final NULL - + (have_dex2oat_isa_variant ? 1 : 0) - + (have_dex2oat_isa_features ? 1 : 0) - + (have_dex2oat_Xms_flag ? 2 : 0) - + (have_dex2oat_Xmx_flag ? 2 : 0) - + (have_dex2oat_compiler_filter_flag ? 1 : 0) - + (have_dex2oat_threads_flag ? 1 : 0) - + (have_dex2oat_swap_fd ? 1 : 0) - + (have_dex2oat_image_fd ? 1 : 0) - + (have_dex2oat_relocation_skip_flag ? 2 : 0) - + (generate_debug_info ? 1 : 0) - + (debuggable ? 1 : 0) - + (have_app_image_format ? 1 : 0) - + dex2oat_flags_count - + (profile_fd == -1 ? 0 : 1) - + (class_loader_context != nullptr ? 1 : 0) - + (has_base_dir ? 1 : 0) - + (have_dex2oat_large_app_threshold ? 1 : 0) - + (disable_cdex ? 1 : 0) - + (generate_minidebug_info ? 1 : 0) - + (target_sdk_version != 0 ? 2 : 0) - + (enable_hidden_api_checks ? 2 : 0) - + (dex_metadata_fd > -1 ? 1 : 0) - + (compilation_reason != nullptr ? 1 : 0)]; - int i = 0; - argv[i++] = dex2oat_bin; - argv[i++] = zip_fd_arg; - argv[i++] = zip_location_arg; - argv[i++] = input_vdex_fd_arg; - argv[i++] = output_vdex_fd_arg; - argv[i++] = oat_fd_arg; - argv[i++] = oat_location_arg; - argv[i++] = instruction_set_arg; - if (have_dex2oat_isa_variant) { - argv[i++] = instruction_set_variant_arg; - } - if (have_dex2oat_isa_features) { - argv[i++] = instruction_set_features_arg; - } - if (have_dex2oat_Xms_flag) { - argv[i++] = RUNTIME_ARG; - argv[i++] = dex2oat_Xms_arg; - } - if (have_dex2oat_Xmx_flag) { - argv[i++] = RUNTIME_ARG; - argv[i++] = dex2oat_Xmx_arg; - } - if (have_dex2oat_compiler_filter_flag) { - argv[i++] = dex2oat_compiler_filter_arg; - } - if (have_dex2oat_threads_flag) { - argv[i++] = dex2oat_threads_arg; - } - if (have_dex2oat_swap_fd) { - argv[i++] = dex2oat_swap_fd; - } - if (have_dex2oat_image_fd) { - argv[i++] = dex2oat_image_fd; - } - if (generate_debug_info) { - argv[i++] = "--generate-debug-info"; - } - if (debuggable) { - argv[i++] = "--debuggable"; - } - if (have_app_image_format) { - argv[i++] = image_format_arg; - } - if (have_dex2oat_large_app_threshold) { - argv[i++] = dex2oat_large_app_threshold_arg; - } - if (dex2oat_flags_count) { - i += split(dex2oat_flags, argv + i); - } - if (have_dex2oat_relocation_skip_flag) { - argv[i++] = RUNTIME_ARG; - argv[i++] = dex2oat_norelocation; - } - if (profile_fd != -1) { - argv[i++] = profile_arg; - } - if (has_base_dir) { - argv[i++] = base_dir; - } - if (class_loader_context != nullptr) { - argv[i++] = class_loader_context_arg; - } - if (generate_minidebug_info) { - argv[i++] = kMinidebugDex2oatFlag; +// ExecVHelper prepares and holds pointers to parsed command line arguments so that no allocations +// need to be performed between the fork and exec. +class ExecVHelper { + public: + // Store a placeholder for the binary name. + ExecVHelper() : args_(1u, std::string()) {} + + void PrepareArgs(const std::string& bin) { + CHECK(!args_.empty()); + CHECK(args_[0].empty()); + args_[0] = bin; + // Write char* into array. + for (const std::string& arg : args_) { + argv_.push_back(arg.c_str()); + } + argv_.push_back(nullptr); // Add null terminator. } - if (disable_cdex) { - argv[i++] = kDisableCompactDexFlag; + + [[ noreturn ]] + void Exec(int exit_code) { + execv(argv_[0], (char * const *)&argv_[0]); + PLOG(ERROR) << "execv(" << argv_[0] << ") failed"; + exit(exit_code); } - if (target_sdk_version != 0) { - argv[i++] = RUNTIME_ARG; - argv[i++] = target_sdk_version_arg; - } - if (enable_hidden_api_checks) { - argv[i++] = RUNTIME_ARG; - argv[i++] = "-Xhidden-api-checks"; - } - - if (dex_metadata_fd > -1) { - argv[i++] = dex_metadata_fd_arg.c_str(); + + // Add an arg if it's not empty. + void AddArg(const std::string& arg) { + if (!arg.empty()) { + args_.push_back(arg); + } } - if(compilation_reason != nullptr) { - argv[i++] = compilation_reason_arg.c_str(); + // Add a runtime arg if it's not empty. + void AddRuntimeArg(const std::string& arg) { + if (!arg.empty()) { + args_.push_back("--runtime-arg"); + args_.push_back(arg); + } } - // Do not add after dex2oat_flags, they should override others for debugging. - argv[i] = NULL; - execv(dex2oat_bin, (char * const *)argv); - PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed"; - exit(DexoptReturnCodes::kDex2oatExec); + protected: + // Holder arrays for backing arg storage. + std::vector<std::string> args_; + + // Argument poiners. + std::vector<const char*> argv_; +}; + +static std::string MapPropertyToArg(const std::string& property, + const std::string& format, + const std::string& default_value = "") { + std::string prop = GetProperty(property, default_value); + if (!prop.empty()) { + return StringPrintf(format.c_str(), prop.c_str()); + } + return ""; } +class RunDex2Oat : public ExecVHelper { + public: + RunDex2Oat(int zip_fd, + int oat_fd, + int input_vdex_fd, + int output_vdex_fd, + int image_fd, + const char* input_file_name, + const char* output_file_name, + int swap_fd, + const char* instruction_set, + const char* compiler_filter, + bool debuggable, + bool post_bootcomplete, + bool background_job_compile, + int profile_fd, + const char* class_loader_context, + int target_sdk_version, + bool enable_hidden_api_checks, + bool generate_compact_dex, + int dex_metadata_fd, + const char* compilation_reason) { + // Get the relative path to the input file. + const char* relative_input_file_name = get_location_from_path(input_file_name); + + std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s"); + std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s"); + + const char* threads_property = post_bootcomplete + ? "dalvik.vm.dex2oat-threads" + : "dalvik.vm.boot-dex2oat-threads"; + std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s"); + + const std::string dex2oat_isa_features_key = + StringPrintf("dalvik.vm.isa.%s.features", instruction_set); + std::string instruction_set_features_arg = + MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s"); + + const std::string dex2oat_isa_variant_key = + StringPrintf("dalvik.vm.isa.%s.variant", instruction_set); + std::string instruction_set_variant_arg = + MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s"); + + const char* dex2oat_norelocation = "-Xnorelocate"; + + const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", ""); + std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags); + ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str()); + + // If we are booting without the real /data, don't spend time compiling. + std::string vold_decrypt = GetProperty("vold.decrypt", ""); + bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" || + vold_decrypt == "1"; + + const std::string resolve_startup_string_arg = + MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings", + "--resolve-startup-const-strings=%s"); + const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false); + + std::string image_format_arg; + if (image_fd >= 0) { + image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s"); + } + + std::string dex2oat_large_app_threshold_arg = + MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s"); + + // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat. + const char* dex2oat_bin = "/system/bin/dex2oat"; + constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd"; + // Do not use dex2oatd for release candidates (give dex2oat more soak time). + bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL"; + if (is_debug_runtime() || + (background_job_compile && is_debuggable_build() && !is_release)) { + if (access(kDex2oatDebugPath, X_OK) == 0) { + dex2oat_bin = kDex2oatDebugPath; + } + } + + bool generate_minidebug_info = kEnableMinidebugInfo && + GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault); + + // clang FORTIFY doesn't let us use strlen in constant array bounds, so we + // use arraysize instead. + std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd); + std::string zip_location_arg = StringPrintf("--zip-location=%s", relative_input_file_name); + std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd); + std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd); + std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd); + std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name); + std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set); + std::string dex2oat_compiler_filter_arg; + std::string dex2oat_swap_fd; + std::string dex2oat_image_fd; + std::string target_sdk_version_arg; + if (target_sdk_version != 0) { + StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version); + } + std::string class_loader_context_arg; + if (class_loader_context != nullptr) { + class_loader_context_arg = StringPrintf("--class-loader-context=%s", + class_loader_context); + } + + if (swap_fd >= 0) { + dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd); + } + if (image_fd >= 0) { + dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd); + } + + // Compute compiler filter. + bool have_dex2oat_relocation_skip_flag = false; + if (skip_compilation) { + dex2oat_compiler_filter_arg = "--compiler-filter=extract"; + have_dex2oat_relocation_skip_flag = true; + } else if (compiler_filter != nullptr) { + dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter); + } + + if (dex2oat_compiler_filter_arg.empty()) { + dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter", + "--compiler-filter=%s"); + } + + // Check whether all apps should be compiled debuggable. + if (!debuggable) { + debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1"; + } + std::string profile_arg; + if (profile_fd != -1) { + profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd); + } + + // Get the directory of the apk to pass as a base classpath directory. + std::string base_dir; + std::string apk_dir(input_file_name); + unsigned long dir_index = apk_dir.rfind('/'); + bool has_base_dir = dir_index != std::string::npos; + if (has_base_dir) { + apk_dir = apk_dir.substr(0, dir_index); + base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str()); + } + + std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd); + + std::string compilation_reason_arg = compilation_reason == nullptr + ? "" + : std::string("--compilation-reason=") + compilation_reason; + + ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name); + + // Disable cdex if update input vdex is true since this combination of options is not + // supported. + const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd); + + AddArg(zip_fd_arg); + AddArg(zip_location_arg); + AddArg(input_vdex_fd_arg); + AddArg(output_vdex_fd_arg); + AddArg(oat_fd_arg); + AddArg(oat_location_arg); + AddArg(instruction_set_arg); + + AddArg(instruction_set_variant_arg); + AddArg(instruction_set_features_arg); + + AddRuntimeArg(dex2oat_Xms_arg); + AddRuntimeArg(dex2oat_Xmx_arg); + + AddArg(resolve_startup_string_arg); + AddArg(dex2oat_compiler_filter_arg); + AddArg(dex2oat_threads_arg); + AddArg(dex2oat_swap_fd); + AddArg(dex2oat_image_fd); + + if (generate_debug_info) { + AddArg("--generate-debug-info"); + } + if (debuggable) { + AddArg("--debuggable"); + } + AddArg(image_format_arg); + AddArg(dex2oat_large_app_threshold_arg); + + if (have_dex2oat_relocation_skip_flag) { + AddRuntimeArg(dex2oat_norelocation); + } + AddArg(profile_arg); + AddArg(base_dir); + AddArg(class_loader_context_arg); + if (generate_minidebug_info) { + AddArg(kMinidebugDex2oatFlag); + } + if (disable_cdex) { + AddArg(kDisableCompactDexFlag); + } + AddArg(target_sdk_version_arg); + if (enable_hidden_api_checks) { + AddRuntimeArg("-Xhidden-api-checks"); + } + + if (dex_metadata_fd > -1) { + AddArg(dex_metadata_fd_arg); + } + + AddArg(compilation_reason_arg); + + // Do not add args after dex2oat_flags, they should override others for debugging. + args_.insert(args_.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end()); + + PrepareArgs(dex2oat_bin); + } +}; + /* * Whether dexopt should use a swap file when compiling an APK. * @@ -580,13 +495,9 @@ static bool ShouldUseSwapFileForDexopt() { } // Check the "override" property. If it exists, return value == "true". - char dex2oat_prop_buf[kPropertyValueMax]; - if (get_property("dalvik.vm.dex2oat-swap", dex2oat_prop_buf, "") > 0) { - if (strcmp(dex2oat_prop_buf, "true") == 0) { - return true; - } else { - return false; - } + std::string dex2oat_prop_buf = GetProperty("dalvik.vm.dex2oat-swap", ""); + if (!dex2oat_prop_buf.empty()) { + return dex2oat_prop_buf == "true"; } // Shortcut for default value. This is an implementation optimization for the process sketched @@ -596,8 +507,7 @@ static bool ShouldUseSwapFileForDexopt() { return true; } - bool is_low_mem = property_get_bool("ro.config.low_ram", false); - if (is_low_mem) { + if (GetBoolProperty("ro.config.low_ram", false)) { return true; } @@ -738,91 +648,91 @@ static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 2; static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3; static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4; -[[ noreturn ]] -static void run_profman(const std::vector<unique_fd>& profile_fds, - const unique_fd& reference_profile_fd, - const std::vector<unique_fd>* apk_fds, - const std::vector<std::string>* dex_locations, - bool copy_and_update) { - const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman"; +class RunProfman : public ExecVHelper { + public: + void SetupArgs(const std::vector<unique_fd>& profile_fds, + const unique_fd& reference_profile_fd, + const std::vector<unique_fd>& apk_fds, + const std::vector<std::string>& dex_locations, + bool copy_and_update) { + const char* profman_bin = + is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman"; - if (copy_and_update) { - CHECK_EQ(1u, profile_fds.size()); - CHECK(apk_fds != nullptr); - CHECK_EQ(1u, apk_fds->size()); - } - std::vector<std::string> profile_args(profile_fds.size()); - for (size_t k = 0; k < profile_fds.size(); k++) { - profile_args[k] = "--profile-file-fd=" + std::to_string(profile_fds[k].get()); - } - std::string reference_profile_arg = "--reference-profile-file-fd=" - + std::to_string(reference_profile_fd.get()); + if (copy_and_update) { + CHECK_EQ(1u, profile_fds.size()); + CHECK_EQ(1u, apk_fds.size()); + } + if (reference_profile_fd != -1) { + AddArg("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get())); + } - std::vector<std::string> apk_args; - if (apk_fds != nullptr) { - for (size_t k = 0; k < apk_fds->size(); k++) { - apk_args.push_back("--apk-fd=" + std::to_string((*apk_fds)[k].get())); + for (const unique_fd& fd : profile_fds) { + AddArg("--profile-file-fd=" + std::to_string(fd.get())); } - } - std::vector<std::string> dex_location_args; - if (dex_locations != nullptr) { - for (size_t k = 0; k < dex_locations->size(); k++) { - dex_location_args.push_back("--dex-location=" + (*dex_locations)[k]); + for (const unique_fd& fd : apk_fds) { + AddArg("--apk-fd=" + std::to_string(fd.get())); } - } - // program name, reference profile fd, the final NULL and the profile fds - const char* argv[3 + profile_args.size() + apk_args.size() - + dex_location_args.size() + (copy_and_update ? 1 : 0)]; - int i = 0; - argv[i++] = profman_bin; - argv[i++] = reference_profile_arg.c_str(); - for (size_t k = 0; k < profile_args.size(); k++) { - argv[i++] = profile_args[k].c_str(); - } - for (size_t k = 0; k < apk_args.size(); k++) { - argv[i++] = apk_args[k].c_str(); + for (const std::string& dex_location : dex_locations) { + AddArg("--dex-location=" + dex_location); + } + + if (copy_and_update) { + AddArg("--copy-and-update-profile-key"); + } + + // Do not add after dex2oat_flags, they should override others for debugging. + PrepareArgs(profman_bin); } - for (size_t k = 0; k < dex_location_args.size(); k++) { - argv[i++] = dex_location_args[k].c_str(); + + void SetupMerge(const std::vector<unique_fd>& profiles_fd, + const unique_fd& reference_profile_fd, + const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>(), + const std::vector<std::string>& dex_locations = std::vector<std::string>()) { + SetupArgs(profiles_fd, + reference_profile_fd, + apk_fds, + dex_locations, + /*copy_and_update=*/false); } - if (copy_and_update) { - argv[i++] = "--copy-and-update-profile-key"; + + void SetupCopyAndUpdate(unique_fd&& profile_fd, + unique_fd&& reference_profile_fd, + unique_fd&& apk_fd, + const std::string& dex_location) { + // The fds need to stay open longer than the scope of the function, so put them into a local + // variable vector. + profiles_fd_.push_back(std::move(profile_fd)); + apk_fds_.push_back(std::move(apk_fd)); + reference_profile_fd_ = std::move(reference_profile_fd); + std::vector<std::string> dex_locations = {dex_location}; + SetupArgs(profiles_fd_, reference_profile_fd_, apk_fds_, dex_locations, + /*copy_and_update=*/true); } - // Do not add after dex2oat_flags, they should override others for debugging. - argv[i] = NULL; + void SetupDump(const std::vector<unique_fd>& profiles_fd, + const unique_fd& reference_profile_fd, + const std::vector<std::string>& dex_locations, + const std::vector<unique_fd>& apk_fds, + const unique_fd& output_fd) { + AddArg("--dump-only"); + AddArg(StringPrintf("--dump-output-to-fd=%d", output_fd.get())); + SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations, + /*copy_and_update=*/false); + } - execv(profman_bin, (char * const *)argv); - PLOG(ERROR) << "execv(" << profman_bin << ") failed"; - exit(DexoptReturnCodes::kProfmanExec); /* only get here on exec failure */ -} + void Exec() { + ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec); + } -[[ noreturn ]] -static void run_profman_merge(const std::vector<unique_fd>& profiles_fd, - const unique_fd& reference_profile_fd, - const std::vector<unique_fd>* apk_fds = nullptr, - const std::vector<std::string>* dex_locations = nullptr) { - run_profman(profiles_fd, reference_profile_fd, apk_fds, dex_locations, - /*copy_and_update*/false); -} + private: + unique_fd reference_profile_fd_; + std::vector<unique_fd> profiles_fd_; + std::vector<unique_fd> apk_fds_; +}; -[[ noreturn ]] -static void run_profman_copy_and_update(unique_fd&& profile_fd, - unique_fd&& reference_profile_fd, - unique_fd&& apk_fd, - const std::string& dex_location) { - std::vector<unique_fd> profiles_fd; - profiles_fd.push_back(std::move(profile_fd)); - std::vector<unique_fd> apk_fds; - apk_fds.push_back(std::move(apk_fd)); - std::vector<std::string> dex_locations; - dex_locations.push_back(dex_location); - run_profman(profiles_fd, reference_profile_fd, &apk_fds, &dex_locations, - /*copy_and_update*/true); -} // Decides if profile guided compilation is needed or not based on existing profiles. // The location is the package name for primary apks or the dex path for secondary dex files. @@ -842,11 +752,13 @@ static bool analyze_profiles(uid_t uid, const std::string& package_name, return false; } + RunProfman profman_merge; + profman_merge.SetupMerge(profiles_fd, reference_profile_fd); pid_t pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ drop_capabilities(uid); - run_profman_merge(profiles_fd, reference_profile_fd); + profman_merge.Exec(); } /* parent */ int return_code = wait_child(pid); @@ -919,42 +831,6 @@ bool analyze_primary_profiles(uid_t uid, const std::string& package_name, return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false); } -[[ noreturn ]] -static void run_profman_dump(const std::vector<unique_fd>& profile_fds, - const unique_fd& reference_profile_fd, - const std::vector<std::string>& dex_locations, - const std::vector<unique_fd>& apk_fds, - const unique_fd& output_fd) { - std::vector<std::string> profman_args; - static const char* PROFMAN_BIN = "/system/bin/profman"; - profman_args.push_back(PROFMAN_BIN); - profman_args.push_back("--dump-only"); - profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd.get())); - if (reference_profile_fd != -1) { - profman_args.push_back(StringPrintf("--reference-profile-file-fd=%d", - reference_profile_fd.get())); - } - for (size_t i = 0; i < profile_fds.size(); i++) { - profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fds[i].get())); - } - for (const std::string& dex_location : dex_locations) { - profman_args.push_back(StringPrintf("--dex-location=%s", dex_location.c_str())); - } - for (size_t i = 0; i < apk_fds.size(); i++) { - profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fds[i].get())); - } - const char **argv = new const char*[profman_args.size() + 1]; - size_t i = 0; - for (const std::string& profman_arg : profman_args) { - argv[i++] = profman_arg.c_str(); - } - argv[i] = NULL; - - execv(PROFMAN_BIN, (char * const *)argv); - PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed"; - exit(DexoptReturnCodes::kProfmanExec); /* only get here on exec failure */ -} - bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name, const std::string& code_path) { std::vector<unique_fd> profile_fds; @@ -991,12 +867,13 @@ bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& p apk_fds.push_back(std::move(apk_fd)); + RunProfman profman_dump; + profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds, output_fd); pid_t pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ drop_capabilities(uid); - run_profman_dump(profile_fds, reference_profile_fd, dex_locations, - apk_fds, output_fd); + profman_dump.Exec(); } /* parent */ int return_code = wait_child(pid); @@ -1306,10 +1183,8 @@ Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, if (!generate_app_image) { return Dex2oatFileWrapper(); } - char app_image_format[kPropertyValueMax]; - bool have_app_image_format = - get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0; - if (!have_app_image_format) { + std::string app_image_format = GetProperty("dalvik.vm.appimageformat", ""); + if (app_image_format.empty()) { return Dex2oatFileWrapper(); } // Recreate is true since we do not want to modify a mapped image. If the app is @@ -1570,70 +1445,60 @@ void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) // The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter. // If this is for a profile guided compilation, profile_was_updated will tell whether or not // the profile has changed. -static void exec_dexoptanalyzer(const std::string& dex_file, int vdex_fd, int oat_fd, - int zip_fd, const std::string& instruction_set, const std::string& compiler_filter, - bool profile_was_updated, bool downgrade, - const char* class_loader_context) { - CHECK_GE(zip_fd, 0); - const char* dexoptanalyzer_bin = - is_debug_runtime() - ? "/system/bin/dexoptanalyzerd" - : "/system/bin/dexoptanalyzer"; - static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; - - if (instruction_set.size() >= MAX_INSTRUCTION_SET_LEN) { - LOG(ERROR) << "Instruction set " << instruction_set - << " longer than max length of " << MAX_INSTRUCTION_SET_LEN; - return; - } - - std::string dex_file_arg = "--dex-file=" + dex_file; - std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd); - std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd); - std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd); - std::string isa_arg = "--isa=" + instruction_set; - std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter; - const char* assume_profile_changed = "--assume-profile-changed"; - const char* downgrade_flag = "--downgrade"; - std::string class_loader_context_arg = "--class-loader-context="; - if (class_loader_context != nullptr) { - class_loader_context_arg += class_loader_context; - } - - // program name, dex file, isa, filter, the final NULL - const int argc = 6 + - (profile_was_updated ? 1 : 0) + - (vdex_fd >= 0 ? 1 : 0) + - (oat_fd >= 0 ? 1 : 0) + - (downgrade ? 1 : 0) + - (class_loader_context != nullptr ? 1 : 0); - const char* argv[argc]; - int i = 0; - argv[i++] = dexoptanalyzer_bin; - argv[i++] = dex_file_arg.c_str(); - argv[i++] = isa_arg.c_str(); - argv[i++] = compiler_filter_arg.c_str(); - if (oat_fd >= 0) { - argv[i++] = oat_fd_arg.c_str(); - } - if (vdex_fd >= 0) { - argv[i++] = vdex_fd_arg.c_str(); - } - argv[i++] = zip_fd_arg.c_str(); - if (profile_was_updated) { - argv[i++] = assume_profile_changed; - } - if (downgrade) { - argv[i++] = downgrade_flag; - } - if (class_loader_context != nullptr) { - argv[i++] = class_loader_context_arg.c_str(); +class RunDexoptAnalyzer : public ExecVHelper { + public: + RunDexoptAnalyzer(const std::string& dex_file, + int vdex_fd, + int oat_fd, + int zip_fd, + const std::string& instruction_set, + const std::string& compiler_filter, + bool profile_was_updated, + bool downgrade, + const char* class_loader_context) { + CHECK_GE(zip_fd, 0); + const char* dexoptanalyzer_bin = + is_debug_runtime() + ? "/system/bin/dexoptanalyzerd" + : "/system/bin/dexoptanalyzer"; + + std::string dex_file_arg = "--dex-file=" + dex_file; + std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd); + std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd); + std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd); + std::string isa_arg = "--isa=" + instruction_set; + std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter; + const char* assume_profile_changed = "--assume-profile-changed"; + const char* downgrade_flag = "--downgrade"; + std::string class_loader_context_arg = "--class-loader-context="; + if (class_loader_context != nullptr) { + class_loader_context_arg += class_loader_context; + } + + // program name, dex file, isa, filter + AddArg(dex_file_arg); + AddArg(isa_arg); + AddArg(compiler_filter_arg); + if (oat_fd >= 0) { + AddArg(oat_fd_arg); + } + if (vdex_fd >= 0) { + AddArg(vdex_fd_arg); + } + AddArg(zip_fd_arg.c_str()); + if (profile_was_updated) { + AddArg(assume_profile_changed); + } + if (downgrade) { + AddArg(downgrade_flag); + } + if (class_loader_context != nullptr) { + AddArg(class_loader_context_arg.c_str()); + } + + PrepareArgs(dexoptanalyzer_bin); } - argv[i] = NULL; - - execv(dexoptanalyzer_bin, (char * const *)argv); - ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno)); -} +}; // Prepares the oat dir for the secondary dex files. static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid, @@ -1885,16 +1750,17 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char /*is_secondary_dex*/true); // Run dexoptanalyzer to get dexopt_needed code. This is not expected to return. - exec_dexoptanalyzer(dex_path, - vdex_file_fd.get(), - oat_file_fd.get(), - zip_fd.get(), - instruction_set, - compiler_filter, profile_was_updated, - downgrade, - class_loader_context); - PLOG(ERROR) << "Failed to exec dexoptanalyzer"; - _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec); + // Note that we do not do it before the fork since opening the files is required to happen + // after forking. + RunDexoptAnalyzer run_dexopt_analyzer(dex_path, + vdex_file_fd.get(), + oat_file_fd.get(), + zip_fd.get(), + instruction_set, + compiler_filter, profile_was_updated, + downgrade, + class_loader_context); + run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec); } /* parent */ @@ -2063,6 +1929,27 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---"; + RunDex2Oat runner(input_fd.get(), + out_oat_fd.get(), + in_vdex_fd.get(), + out_vdex_fd.get(), + image_fd.get(), + dex_path, + out_oat_path, + swap_fd.get(), + instruction_set, + compiler_filter, + debuggable, + boot_complete, + background_job_compile, + reference_profile_fd.get(), + class_loader_context, + target_sdk_version, + enable_hidden_api_checks, + generate_compact_dex, + dex_metadata_fd.get(), + compilation_reason); + pid_t pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ @@ -2074,26 +1961,7 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins _exit(DexoptReturnCodes::kFlock); } - run_dex2oat(input_fd.get(), - out_oat_fd.get(), - in_vdex_fd.get(), - out_vdex_fd.get(), - image_fd.get(), - dex_path, - out_oat_path, - swap_fd.get(), - instruction_set, - compiler_filter, - debuggable, - boot_complete, - background_job_compile, - reference_profile_fd.get(), - class_loader_context, - target_sdk_version, - enable_hidden_api_checks, - generate_compact_dex, - dex_metadata_fd.get(), - compilation_reason); + runner.Exec(DexoptReturnCodes::kDex2oatExec); } else { int res = wait_child(pid); if (res == 0) { @@ -2421,18 +2289,14 @@ static bool move_ab_path(const std::string& b_path, const std::string& a_path) { bool move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) { // Get the current slot suffix. No suffix, no A/B. - std::string slot_suffix; - { - char buf[kPropertyValueMax]; - if (get_property("ro.boot.slot_suffix", buf, nullptr) <= 0) { - return false; - } - slot_suffix = buf; + const std::string slot_suffix = GetProperty("ro.boot.slot_suffix", ""); + if (slot_suffix.empty()) { + return false; + } - if (!ValidateTargetSlotSuffix(slot_suffix)) { - LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix; - return false; - } + if (!ValidateTargetSlotSuffix(slot_suffix)) { + LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix; + return false; } // Validate other inputs. @@ -2661,11 +2525,13 @@ static bool create_app_profile_snapshot(int32_t app_id, return false; } + RunProfman args; + args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations); pid_t pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ drop_capabilities(app_shared_gid); - run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations); + args.Exec(); } /* parent */ @@ -2689,6 +2555,13 @@ static bool create_boot_image_profile_snapshot(const std::string& package_name, return false; } + // Return false for empty class path since it may otherwise return true below if profiles is + // empty. + if (classpath.empty()) { + PLOG(ERROR) << "Class path is empty"; + return false; + } + // Open and create the snapshot profile. unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name); @@ -2738,6 +2611,8 @@ static bool create_boot_image_profile_snapshot(const std::string& package_name, profiles_fd.push_back(std::move(fd)); } } + RunProfman args; + args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations); pid_t pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ @@ -2745,7 +2620,7 @@ static bool create_boot_image_profile_snapshot(const std::string& package_name, // The introduction of new access flags into boot jars causes them to // fail dex file verification. - run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations); + args.Exec(); } /* parent */ @@ -2799,6 +2674,11 @@ bool prepare_app_profile(const std::string& package_name, return false; } + RunProfman args; + args.SetupCopyAndUpdate(std::move(dex_metadata_fd), + std::move(ref_profile_fd), + std::move(apk_fd), + code_path); pid_t pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ @@ -2806,10 +2686,7 @@ bool prepare_app_profile(const std::string& package_name, drop_capabilities(app_shared_gid); // The copy and update takes ownership over the fds. - run_profman_copy_and_update(std::move(dex_metadata_fd), - std::move(ref_profile_fd), - std::move(apk_fd), - code_path); + args.Exec(); } /* parent */ diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp index 95ed2fff35..673ff0d513 100644 --- a/cmds/installd/installd.cpp +++ b/cmds/installd/installd.cpp @@ -107,7 +107,7 @@ static int initialize_directories() { DIR *dir; struct dirent *dirent; dir = opendir("/data/user"); - if (dir != NULL) { + if (dir != nullptr) { while ((dirent = readdir(dir))) { const char *name = dirent->d_name; @@ -146,10 +146,10 @@ static int initialize_directories() { closedir(dir); if (access(keychain_added_dir, F_OK) == 0) { - delete_dir_contents(keychain_added_dir, 1, 0); + delete_dir_contents(keychain_added_dir, 1, nullptr); } if (access(keychain_removed_dir, F_OK) == 0) { - delete_dir_contents(keychain_removed_dir, 1, 0); + delete_dir_contents(keychain_removed_dir, 1, nullptr); } } diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index f216c53be4..79e6859ce7 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -143,6 +143,20 @@ static const char kDexFile[] = "AAAACADojmFLPcugSwoBAAAUAgAACwAYAAAAAAAAAAAAoIEAAAAAY2xhc3Nlcy5kZXhVVAUAA/Ns" "+ll1eAsAAQQj5QIABIgTAABQSwUGAAAAAAEAAQBRAAAATwEAAAAA"; +class DexoptTestEnvTest : public testing::Test { +}; + +TEST_F(DexoptTestEnvTest, CheckSelinux) { + ASSERT_EQ(1, is_selinux_enabled()); + + // Crude cutout for virtual devices. +#if !defined(__i386__) && !defined(__x86_64__) + constexpr bool kIsX86 = false; +#else + constexpr bool kIsX86 = true; +#endif + ASSERT_TRUE(1 == security_getenforce() || kIsX86 || true /* b/119032200 */); +} class DexoptTest : public testing::Test { protected: diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index 8672206d17..74ad1841a5 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -43,6 +43,7 @@ #define DEBUG_XATTRS 0 using android::base::EndsWith; +using android::base::Fdopendir; using android::base::StringPrintf; using android::base::unique_fd; @@ -310,7 +311,7 @@ std::vector<userid_t> get_known_users(const char* volume_uuid) { std::string path(create_data_path(volume_uuid) + "/" + SECONDARY_USER_PREFIX); DIR* dir = opendir(path.c_str()); - if (dir == NULL) { + if (dir == nullptr) { // Unable to discover other users, but at least return owner PLOG(ERROR) << "Failed to opendir " << path; return users; @@ -340,13 +341,13 @@ int calculate_tree_size(const std::string& path, int64_t* size, FTSENT *p; int64_t matchedSize = 0; char *argv[] = { (char*) path.c_str(), nullptr }; - if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) { + if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) { if (errno != ENOENT) { PLOG(ERROR) << "Failed to fts_open " << path; } return -1; } - while ((p = fts_read(fts)) != NULL) { + while ((p = fts_read(fts)) != nullptr) { switch (p->fts_info) { case FTS_D: case FTS_DEFAULT: @@ -469,7 +470,7 @@ static int _delete_dir_contents(DIR *d, continue; } subdir = fdopendir(subfd); - if (subdir == NULL) { + if (subdir == nullptr) { ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); close(subfd); result = -1; @@ -495,11 +496,11 @@ static int _delete_dir_contents(DIR *d, } int delete_dir_contents(const std::string& pathname, bool ignore_if_missing) { - return delete_dir_contents(pathname.c_str(), 0, NULL, ignore_if_missing); + return delete_dir_contents(pathname.c_str(), 0, nullptr, ignore_if_missing); } int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) { - return delete_dir_contents(pathname.c_str(), 1, NULL, ignore_if_missing); + return delete_dir_contents(pathname.c_str(), 1, nullptr, ignore_if_missing); } int delete_dir_contents(const char *pathname, @@ -511,7 +512,7 @@ int delete_dir_contents(const char *pathname, DIR *d; d = opendir(pathname); - if (d == NULL) { + if (d == nullptr) { if (ignore_if_missing && (errno == ENOENT)) { return 0; } @@ -540,12 +541,12 @@ int delete_dir_contents_fd(int dfd, const char *name) return -1; } d = fdopendir(fd); - if (d == NULL) { + if (d == nullptr) { ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); close(fd); return -1; } - res = _delete_dir_contents(d, 0); + res = _delete_dir_contents(d, nullptr); closedir(d); return res; } @@ -573,7 +574,7 @@ static int _copy_dir_files(int sdfd, int ddfd, uid_t owner, gid_t group) } DIR *ds = fdopendir(sdfd); - if (ds == NULL) { + if (ds == nullptr) { ALOGE("Couldn't fdopendir: %s\n", strerror(errno)); return -1; } @@ -619,18 +620,18 @@ int copy_dir_files(const char *srcname, uid_t group) { int res = 0; - DIR *ds = NULL; - DIR *dd = NULL; + DIR *ds = nullptr; + DIR *dd = nullptr; ds = opendir(srcname); - if (ds == NULL) { + if (ds == nullptr) { ALOGE("Couldn't opendir %s: %s\n", srcname, strerror(errno)); return -errno; } mkdir(dstname, 0600); dd = opendir(dstname); - if (dd == NULL) { + if (dd == nullptr) { ALOGE("Couldn't opendir %s: %s\n", dstname, strerror(errno)); closedir(ds); return -errno; @@ -964,11 +965,11 @@ int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t ta FTS *fts; FTSENT *p; char *argv[] = { (char*) path.c_str(), nullptr }; - if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) { + if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) { PLOG(ERROR) << "Failed to fts_open " << path; return -1; } - while ((p = fts_read(fts)) != NULL) { + while ((p = fts_read(fts)) != nullptr) { switch (p->fts_info) { case FTS_DP: if (chmod(p->fts_path, target_mode) != 0) { @@ -1036,8 +1037,8 @@ static bool collect_profiles(DIR* d, continue; } - DIR* subdir = fdopendir(subdir_fd); - if (subdir == NULL) { + DIR* subdir = Fdopendir(std::move(subdir_fd)); + if (subdir == nullptr) { PLOG(WARNING) << "Could not open dir path " << local_path; result = false; continue; @@ -1055,7 +1056,7 @@ static bool collect_profiles(DIR* d, bool collect_profiles(std::vector<std::string>* profiles_paths) { DIR* d = opendir(android_profiles_dir.c_str()); - if (d == NULL) { + if (d == nullptr) { return false; } else { return collect_profiles(d, android_profiles_dir, profiles_paths); diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index 5829c4fd14..d05724a8f0 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -36,8 +36,6 @@ #define BYPASS_QUOTA 0 #define BYPASS_SDCARDFS 0 -#define APPLY_HARD_QUOTAS 0 - namespace android { namespace installd { diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 1bd7c4fb42..f6cc3afc97 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -115,6 +115,7 @@ const String16& BBinder::getInterfaceDescriptor() const return sEmptyDescriptor; } +// NOLINTNEXTLINE(google-default-arguments) status_t BBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -137,6 +138,7 @@ status_t BBinder::transact( return err; } +// NOLINTNEXTLINE(google-default-arguments) status_t BBinder::linkToDeath( const sp<DeathRecipient>& /*recipient*/, void* /*cookie*/, uint32_t /*flags*/) @@ -144,6 +146,7 @@ status_t BBinder::linkToDeath( return INVALID_OPERATION; } +// NOLINTNEXTLINE(google-default-arguments) status_t BBinder::unlinkToDeath( const wp<DeathRecipient>& /*recipient*/, void* /*cookie*/, uint32_t /*flags*/, wp<DeathRecipient>* /*outRecipient*/) @@ -208,6 +211,7 @@ BBinder::~BBinder() } +// NOLINTNEXTLINE(google-default-arguments) status_t BBinder::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t /*flags*/) { diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 734212626a..ec170f7a65 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -206,6 +206,7 @@ status_t BpBinder::dump(int fd, const Vector<String16>& args) return err; } +// NOLINTNEXTLINE(google-default-arguments) status_t BpBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -220,6 +221,7 @@ status_t BpBinder::transact( return DEAD_OBJECT; } +// NOLINTNEXTLINE(google-default-arguments) status_t BpBinder::linkToDeath( const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags) { @@ -254,6 +256,7 @@ status_t BpBinder::linkToDeath( return DEAD_OBJECT; } +// NOLINTNEXTLINE(google-default-arguments) status_t BpBinder::unlinkToDeath( const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags, wp<DeathRecipient>* outRecipient) diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp index f9ec593f77..2f4dbeea18 100644 --- a/libs/binder/IAppOpsCallback.cpp +++ b/libs/binder/IAppOpsCallback.cpp @@ -49,6 +49,7 @@ IMPLEMENT_META_INTERFACE(AppOpsCallback, "com.android.internal.app.IAppOpsCallba // ---------------------------------------------------------------------- +// NOLINTNEXTLINE(google-default-arguments) status_t BnAppOpsCallback::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index 068664b418..fb0d521cac 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -129,6 +129,7 @@ IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService // ---------------------------------------------------------------------- +// NOLINTNEXTLINE(google-default-arguments) status_t BnAppOpsService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp index ad1e69faeb..b307e3e7b5 100644 --- a/libs/binder/IBatteryStats.cpp +++ b/libs/binder/IBatteryStats.cpp @@ -136,6 +136,7 @@ IMPLEMENT_META_INTERFACE(BatteryStats, "com.android.internal.app.IBatteryStats") // ---------------------------------------------------------------------- +// NOLINTNEXTLINE(google-default-arguments) status_t BnBatteryStats::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp index 507ce53b66..307bc28c0e 100644 --- a/libs/binder/IMemory.cpp +++ b/libs/binder/IMemory.cpp @@ -129,6 +129,7 @@ class BpMemory : public BpInterface<IMemory> public: explicit BpMemory(const sp<IBinder>& impl); virtual ~BpMemory(); + // NOLINTNEXTLINE(google-default-arguments) virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const; private: @@ -180,6 +181,7 @@ BpMemory::~BpMemory() { } +// NOLINTNEXTLINE(google-default-arguments) sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const { if (mHeap == nullptr) { @@ -224,6 +226,7 @@ BnMemory::BnMemory() { BnMemory::~BnMemory() { } +// NOLINTNEXTLINE(google-default-arguments) status_t BnMemory::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -383,6 +386,7 @@ BnMemoryHeap::BnMemoryHeap() { BnMemoryHeap::~BnMemoryHeap() { } +// NOLINTNEXTLINE(google-default-arguments) status_t BnMemoryHeap::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp index 89ebc6c1aa..6b99150edf 100644 --- a/libs/binder/IPermissionController.cpp +++ b/libs/binder/IPermissionController.cpp @@ -109,6 +109,7 @@ IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController // ---------------------------------------------------------------------- +// NOLINTNEXTLINE(google-default-arguments) status_t BnPermissionController::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp index 14b5259536..159763d5bf 100644 --- a/libs/binder/IResultReceiver.cpp +++ b/libs/binder/IResultReceiver.cpp @@ -48,6 +48,7 @@ IMPLEMENT_META_INTERFACE(ResultReceiver, "com.android.internal.os.IResultReceive // ---------------------------------------------------------------------- +// NOLINTNEXTLINE(google-default-arguments) status_t BnResultReceiver::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp index dd4a65ee84..6c697decca 100644 --- a/libs/binder/IShellCallback.cpp +++ b/libs/binder/IShellCallback.cpp @@ -58,6 +58,7 @@ IMPLEMENT_META_INTERFACE(ShellCallback, "com.android.internal.os.IShellCallback" // ---------------------------------------------------------------------- +// NOLINTNEXTLINE(google-default-arguments) status_t BnShellCallback::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index b3ae09b405..07d5c4bb2c 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -2239,8 +2239,30 @@ int Parcel::readParcelFileDescriptor() const int32_t hasComm = readInt32(); int fd = readFileDescriptor(); if (hasComm != 0) { - // skip - readFileDescriptor(); + // detach (owned by the binder driver) + int comm = readFileDescriptor(); + + // warning: this must be kept in sync with: + // frameworks/base/core/java/android/os/ParcelFileDescriptor.java + enum ParcelFileDescriptorStatus { + DETACHED = 2, + }; + +#if BYTE_ORDER == BIG_ENDIAN + const int32_t message = ParcelFileDescriptorStatus::DETACHED; +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + const int32_t message = __builtin_bswap32(ParcelFileDescriptorStatus::DETACHED); +#endif + + ssize_t written = TEMP_FAILURE_RETRY( + ::write(comm, &message, sizeof(message))); + + if (written == -1 || written != sizeof(message)) { + ALOGW("Failed to detach ParcelFileDescriptor written: %zd err: %s", + written, strerror(errno)); + return BAD_TYPE; + } } return fd; } diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index 0b60b4e5fd..c251468bdb 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -34,15 +34,18 @@ public: virtual status_t pingBinder(); virtual status_t dump(int fd, const Vector<String16>& args); + // NOLINTNEXTLINE(google-default-arguments) virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); + // NOLINTNEXTLINE(google-default-arguments) virtual status_t linkToDeath(const sp<DeathRecipient>& recipient, void* cookie = nullptr, uint32_t flags = 0); + // NOLINTNEXTLINE(google-default-arguments) virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient, void* cookie = nullptr, uint32_t flags = 0, @@ -60,6 +63,7 @@ public: protected: virtual ~BBinder(); + // NOLINTNEXTLINE(google-default-arguments) virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index c4c8ba3e74..1d4f88113a 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -41,14 +41,18 @@ public: virtual status_t pingBinder(); virtual status_t dump(int fd, const Vector<String16>& args); + // NOLINTNEXTLINE(google-default-arguments) virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); + // NOLINTNEXTLINE(google-default-arguments) virtual status_t linkToDeath(const sp<DeathRecipient>& recipient, void* cookie = nullptr, uint32_t flags = 0); + + // NOLINTNEXTLINE(google-default-arguments) virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient, void* cookie = nullptr, uint32_t flags = 0, diff --git a/libs/binder/include/binder/IAppOpsCallback.h b/libs/binder/include/binder/IAppOpsCallback.h index e5b12a9720..b500219e37 100644 --- a/libs/binder/include/binder/IAppOpsCallback.h +++ b/libs/binder/include/binder/IAppOpsCallback.h @@ -43,6 +43,7 @@ public: class BnAppOpsCallback : public BnInterface<IAppOpsCallback> { public: + // NOLINTNEXTLINE(google-default-arguments) virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h index f0c5e1743d..78078513ff 100644 --- a/libs/binder/include/binder/IAppOpsService.h +++ b/libs/binder/include/binder/IAppOpsService.h @@ -67,6 +67,7 @@ public: class BnAppOpsService : public BnInterface<IAppOpsService> { public: + // NOLINTNEXTLINE(google-default-arguments) virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, diff --git a/libs/binder/include/binder/IBatteryStats.h b/libs/binder/include/binder/IBatteryStats.h index 59e806c177..48da865702 100644 --- a/libs/binder/include/binder/IBatteryStats.h +++ b/libs/binder/include/binder/IBatteryStats.h @@ -68,6 +68,7 @@ public: class BnBatteryStats : public BnInterface<IBatteryStats> { public: + // NOLINTNEXTLINE(google-default-arguments) virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h index 3f0dad0f25..14edcbe72a 100644 --- a/libs/binder/include/binder/IBinder.h +++ b/libs/binder/include/binder/IBinder.h @@ -86,6 +86,7 @@ public: Vector<String16>& args, const sp<IShellCallback>& callback, const sp<IResultReceiver>& resultReceiver); + // NOLINTNEXTLINE(google-default-arguments) virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, @@ -131,6 +132,7 @@ public: * (Nor should you need to, as there is nothing useful you can * directly do with it now that it has passed on.) */ + // NOLINTNEXTLINE(google-default-arguments) virtual status_t linkToDeath(const sp<DeathRecipient>& recipient, void* cookie = nullptr, uint32_t flags = 0) = 0; @@ -142,6 +144,7 @@ public: * supply a NULL @a recipient, and the recipient previously * added with that cookie will be unlinked. */ + // NOLINTNEXTLINE(google-default-arguments) virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient, void* cookie = nullptr, uint32_t flags = 0, diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h index 3099bf5fb8..db9f53a797 100644 --- a/libs/binder/include/binder/IMemory.h +++ b/libs/binder/include/binder/IMemory.h @@ -54,7 +54,8 @@ public: class BnMemoryHeap : public BnInterface<IMemoryHeap> { public: - virtual status_t onTransact( + // NOLINTNEXTLINE(google-default-arguments) + virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, @@ -72,6 +73,7 @@ class IMemory : public IInterface public: DECLARE_META_INTERFACE(Memory) + // NOLINTNEXTLINE(google-default-arguments) virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const = 0; // helpers @@ -84,6 +86,7 @@ public: class BnMemory : public BnInterface<IMemory> { public: + // NOLINTNEXTLINE(google-default-arguments) virtual status_t onTransact( uint32_t code, const Parcel& data, diff --git a/libs/binder/include/binder/IPermissionController.h b/libs/binder/include/binder/IPermissionController.h index 3ec459fc32..26a1b23a9a 100644 --- a/libs/binder/include/binder/IPermissionController.h +++ b/libs/binder/include/binder/IPermissionController.h @@ -56,6 +56,7 @@ public: class BnPermissionController : public BnInterface<IPermissionController> { public: + // NOLINTNEXTLINE(google-default-arguments) virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, diff --git a/libs/binder/include/binder/IResultReceiver.h b/libs/binder/include/binder/IResultReceiver.h index e494fba0b8..00b3d8954c 100644 --- a/libs/binder/include/binder/IResultReceiver.h +++ b/libs/binder/include/binder/IResultReceiver.h @@ -41,6 +41,7 @@ public: class BnResultReceiver : public BnInterface<IResultReceiver> { public: + // NOLINTNEXTLINE(google-default-arguments) virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index a998529cd8..e5d8ea67de 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -61,6 +61,7 @@ public: /** * Register a service. */ + // NOLINTNEXTLINE(google-default-arguments) virtual status_t addService(const String16& name, const sp<IBinder>& service, bool allowIsolated = false, int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0; @@ -68,6 +69,7 @@ public: /** * Return list of all existing services. */ + // NOLINTNEXTLINE(google-default-arguments) virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0; enum { diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h index b47e995183..67156787d3 100644 --- a/libs/binder/include/binder/IShellCallback.h +++ b/libs/binder/include/binder/IShellCallback.h @@ -42,6 +42,7 @@ public: class BnShellCallback : public BnInterface<IShellCallback> { public: + // NOLINTNEXTLINE(google-default-arguments) virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h index d81789e399..9937ad6a29 100644 --- a/libs/binder/include/binder/IUidObserver.h +++ b/libs/binder/include/binder/IUidObserver.h @@ -47,6 +47,7 @@ public: class BnUidObserver : public BnInterface<IUidObserver> { public: + // NOLINTNEXTLINE(google-default-arguments) virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, diff --git a/libs/binder/ndk/.clang-format b/libs/binder/ndk/.clang-format new file mode 100644 index 0000000000..9a9d936f15 --- /dev/null +++ b/libs/binder/ndk/.clang-format @@ -0,0 +1,10 @@ +BasedOnStyle: Google +ColumnLimit: 100 +IndentWidth: 4 +ContinuationIndentWidth: 8 +PointerAlignment: Left +TabWidth: 4 +AllowShortFunctionsOnASingleLine: Inline +PointerAlignment: Left +TabWidth: 4 +UseTab: Never diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp index 5461b4f719..14ce4cba19 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -38,6 +38,10 @@ cc_library { "libbinder", "libutils", ], + + cpp_std: "c++17", + + version_script: "libbinder_ndk.map.txt", } ndk_headers { diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp index 896c5c13b2..f9c8c8a0ff 100644 --- a/libs/binder/ndk/ibinder.cpp +++ b/libs/binder/ndk/ibinder.cpp @@ -22,6 +22,7 @@ #include "status_internal.h" #include <android-base/logging.h> +#include <binder/IPCThreadState.h> using DeathRecipient = ::android::IBinder::DeathRecipient; @@ -45,7 +46,7 @@ static bool has(const sp<IBinder>& binder) { return binder != nullptr && binder->findObject(kId) == kValue; } -} // namespace ABBinderTag +} // namespace ABBinderTag namespace ABpBinderTag { @@ -60,7 +61,7 @@ void clean(const void* id, void* obj, void* cookie) { delete static_cast<Value*>(obj); }; -} // namespace ABpBinderTag +} // namespace ABpBinderTag AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {} AIBinder::~AIBinder() {} @@ -91,7 +92,7 @@ bool AIBinder::associateClass(const AIBinder_Class* clazz) { return false; } - CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor + CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor String8 descriptor(getBinder()->getInterfaceDescriptor()); if (descriptor != newDescriptor) { @@ -107,7 +108,7 @@ bool AIBinder::associateClass(const AIBinder_Class* clazz) { } ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData) - : AIBinder(clazz), BBinder(), mUserData(userData) { + : AIBinder(clazz), BBinder(), mUserData(userData) { CHECK(clazz != nullptr); } ABBinder::~ABBinder() { @@ -136,7 +137,7 @@ status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parce } ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder) - : AIBinder(nullptr /*clazz*/), BpRefBase(binder) { + : AIBinder(nullptr /*clazz*/), BpRefBase(binder) { CHECK(binder != nullptr); } ABpBinder::~ABpBinder() {} @@ -214,10 +215,10 @@ AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder) { AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate, AIBinder_Class_onDestroy onDestroy, AIBinder_Class_onTransact onTransact) - : onCreate(onCreate), - onDestroy(onDestroy), - onTransact(onTransact), - mInterfaceDescriptor(interfaceDescriptor) {} + : onCreate(onCreate), + onDestroy(onDestroy), + onTransact(onTransact), + mInterfaceDescriptor(interfaceDescriptor) {} AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate, @@ -239,7 +240,7 @@ void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinde } AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied) - : mOnDied(onDied) { + : mOnDied(onDied) { CHECK(onDied != nullptr); } @@ -302,7 +303,7 @@ AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) { bool AIBinder_isRemote(const AIBinder* binder) { if (binder == nullptr) { - return true; + return false; } return binder->isRemote(); @@ -346,6 +347,14 @@ binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient return recipient->unlinkToDeath(binder, cookie); } +uid_t AIBinder_getCallingUid() { + return ::android::IPCThreadState::self()->getCallingUid(); +} + +pid_t AIBinder_getCallingPid() { + return ::android::IPCThreadState::self()->getCallingPid(); +} + void AIBinder_incStrong(AIBinder* binder) { if (binder == nullptr) { LOG(ERROR) << __func__ << ": on null binder"; diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h index 5b6bc946a8..ac592ea4f7 100644 --- a/libs/binder/ndk/ibinder_internal.h +++ b/libs/binder/ndk/ibinder_internal.h @@ -49,7 +49,7 @@ struct AIBinder : public virtual ::android::RefBase { return binder->remoteBinder() != nullptr; } -private: + private: // AIBinder instance is instance of this class for a local object. In order to transact on a // remote object, this also must be set for simplicity (although right now, only the // interfaceDescriptor from it is used). @@ -69,7 +69,7 @@ struct ABBinder : public AIBinder, public ::android::BBinder { ::android::status_t onTransact(uint32_t code, const ::android::Parcel& data, ::android::Parcel* reply, binder_flags_t flags) override; -private: + private: ABBinder(const AIBinder_Class* clazz, void* userData); // only thing that should create an ABBinder @@ -96,7 +96,7 @@ struct ABpBinder : public AIBinder, public ::android::BpRefBase { ::android::sp<::android::IBinder> getBinder() override { return remote(); } ABpBinder* asABpBinder() override { return this; } -private: + private: ABpBinder(const ::android::sp<::android::IBinder>& binder); }; @@ -110,7 +110,7 @@ struct AIBinder_Class { const AIBinder_Class_onDestroy onDestroy; const AIBinder_Class_onTransact onTransact; -private: + private: // This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to // one. const ::android::String16 mInterfaceDescriptor; @@ -128,14 +128,14 @@ struct AIBinder_DeathRecipient { struct TransferDeathRecipient : ::android::IBinder::DeathRecipient { TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie, const AIBinder_DeathRecipient_onBinderDied& onDied) - : mWho(who), mCookie(cookie), mOnDied(onDied) {} + : mWho(who), mCookie(cookie), mOnDied(onDied) {} void binderDied(const ::android::wp<::android::IBinder>& who) override; const ::android::wp<::android::IBinder>& getWho() { return mWho; } void* getCookie() { return mCookie; } - private: + private: ::android::wp<::android::IBinder> mWho; void* mCookie; const AIBinder_DeathRecipient_onBinderDied& mOnDied; @@ -145,7 +145,7 @@ struct AIBinder_DeathRecipient { binder_status_t linkToDeath(AIBinder* binder, void* cookie); binder_status_t unlinkToDeath(AIBinder* binder, void* cookie); -private: + private: std::mutex mDeathRecipientsMutex; std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients; AIBinder_DeathRecipient_onBinderDied mOnDied; diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_apex/android/binder_manager.h index b8f38ba88b..80b6c07025 100644 --- a/libs/binder/ndk/include_apex/android/binder_manager.h +++ b/libs/binder/ndk/include_apex/android/binder_manager.h @@ -17,11 +17,18 @@ #pragma once #include <android/binder_ibinder.h> +#include <android/binder_status.h> __BEGIN_DECLS /** - * This registers the service with the default service manager under this instance name. + * This registers the service with the default service manager under this instance name. This does + * not take ownership of binder. + * + * \param binder object to register globally with the service manager. + * \param instance identifier of the service. This will be used to lookup the service. + * + * \return STATUS_OK on success. */ binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance); @@ -29,6 +36,8 @@ binder_status_t AServiceManager_addService(AIBinder* binder, const char* instanc * Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on * it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible * for calling AIBinder_decStrong). + * + * \param instance identifier of the service used to lookup the service. */ __attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance); diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h index cc0a29d18a..c6fcaa48aa 100644 --- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h @@ -32,8 +32,7 @@ #include <assert.h> -#ifdef __cplusplus - +#include <unistd.h> #include <cstddef> namespace ndk { @@ -42,7 +41,7 @@ namespace ndk { * Represents one strong pointer to an AIBinder object. */ class SpAIBinder { -public: + public: /** * Takes ownership of one strong refcount of binder. */ @@ -106,30 +105,30 @@ public: */ AIBinder** getR() { return &mBinder; } -private: + private: AIBinder* mBinder = nullptr; }; /** * This baseclass owns a single object, used to make various classes RAII. */ -template <typename T, void (*Destroy)(T*)> +template <typename T, typename R, R (*Destroy)(T), T DEFAULT> class ScopedAResource { -public: + public: /** * Takes ownership of t. */ - explicit ScopedAResource(T* t = nullptr) : mT(t) {} + explicit ScopedAResource(T t = DEFAULT) : mT(t) {} /** * This deletes the underlying object if it exists. See set. */ - ~ScopedAResource() { set(nullptr); } + ~ScopedAResource() { set(DEFAULT); } /** * Takes ownership of t. */ - void set(T* t) { + void set(T t) { Destroy(mT); mT = t; } @@ -137,12 +136,12 @@ public: /** * This returns the underlying object to be modified but does not affect ownership. */ - T* get() { return mT; } + T get() { return mT; } /** * This returns the const underlying object but does not affect ownership. */ - const T* get() const { return mT; } + const T get() const { return mT; } /** * This allows the value in this class to be set from beneath it. If you call this method and @@ -156,7 +155,7 @@ public: * Other usecases are discouraged. * */ - T** getR() { return &mT; } + T* getR() { return &mT; } // copy-constructing, or move/copy assignment is disallowed ScopedAResource(const ScopedAResource&) = delete; @@ -164,17 +163,19 @@ public: ScopedAResource& operator=(ScopedAResource&&) = delete; // move-constructing is okay - ScopedAResource(ScopedAResource&&) = default; + ScopedAResource(ScopedAResource&& other) : mT(std::move(other.mT)) { + other.mT = DEFAULT; + } -private: - T* mT; + private: + T mT; }; /** * Convenience wrapper. See AParcel. */ -class ScopedAParcel : public ScopedAResource<AParcel, AParcel_delete> { -public: +class ScopedAParcel : public ScopedAResource<AParcel*, void, AParcel_delete, nullptr> { + public: /** * Takes ownership of a. */ @@ -186,8 +187,8 @@ public: /** * Convenience wrapper. See AStatus. */ -class ScopedAStatus : public ScopedAResource<AStatus, AStatus_delete> { -public: +class ScopedAStatus : public ScopedAResource<AStatus*, void, AStatus_delete, nullptr> { + public: /** * Takes ownership of a. */ @@ -199,19 +200,25 @@ public: * See AStatus_isOk. */ bool isOk() { return get() != nullptr && AStatus_isOk(get()); } + + /** + * Convenience method for okay status. + */ + static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); } }; /** * Convenience wrapper. See AIBinder_DeathRecipient. */ class ScopedAIBinder_DeathRecipient - : public ScopedAResource<AIBinder_DeathRecipient, AIBinder_DeathRecipient_delete> { -public: + : public ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete, + nullptr> { + public: /** * Takes ownership of a. */ explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr) - : ScopedAResource(a) {} + : ScopedAResource(a) {} ~ScopedAIBinder_DeathRecipient() {} ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default; }; @@ -219,8 +226,9 @@ public: /** * Convenience wrapper. See AIBinder_Weak. */ -class ScopedAIBinder_Weak : public ScopedAResource<AIBinder_Weak, AIBinder_Weak_delete> { -public: +class ScopedAIBinder_Weak + : public ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> { + public: /** * Takes ownership of a. */ @@ -234,8 +242,19 @@ public: SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); } }; -} // namespace ndk +/** + * Convenience wrapper for a file descriptor. + */ +class ScopedFileDescriptor : public ScopedAResource<int, int, close, -1> { + public: + /** + * Takes ownership of a. + */ + explicit ScopedFileDescriptor(int a = -1) : ScopedAResource(a) {} + ~ScopedFileDescriptor() {} + ScopedFileDescriptor(ScopedFileDescriptor&&) = default; +}; -#endif // __cplusplus +} // namespace ndk /** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h index c222c161f5..9c6c55e736 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h @@ -28,6 +28,7 @@ #include <stdint.h> #include <sys/cdefs.h> +#include <sys/types.h> #include <android/binder_parcel.h> #include <android/binder_status.h> @@ -126,8 +127,9 @@ typedef struct AIBinder_DeathRecipient AIBinder_DeathRecipient; /** * This is called whenever a new AIBinder object is needed of a specific class. * - * These arguments are passed from AIBinder_new. The return value is stored and can be retrieved - * using AIBinder_getUserData. + * \param args these can be used to construct a new class. These are passed from AIBinder_new. + * \return this is the userdata representing the class. It can be retrieved using + * AIBinder_getUserData. */ typedef void* (*AIBinder_Class_onCreate)(void* args); @@ -135,23 +137,41 @@ typedef void* (*AIBinder_Class_onCreate)(void* args); * This is called whenever an AIBinder object is no longer referenced and needs destroyed. * * Typically, this just deletes whatever the implementation is. + * + * \param userData this is the same object returned by AIBinder_Class_onCreate */ typedef void (*AIBinder_Class_onDestroy)(void* userData); /** * This is called whenever a transaction needs to be processed by a local implementation. + * + * \param binder the object being transacted on. + * \param code implementation-specific code representing which transaction should be taken. + * \param in the implementation-specific input data to this transaction. + * \param out the implementation-specific output data to this transaction. + * + * \return the implementation-specific output code. This may be forwarded from another service, the + * result of a parcel read or write, or another error as is applicable to the specific + * implementation. Usually, implementation-specific error codes are written to the output parcel, + * and the transaction code is reserved for kernel errors or error codes that have been repeated + * from subsequent transactions. */ typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, transaction_code_t code, const AParcel* in, AParcel* out); /** - * An interfaceDescriptor uniquely identifies the type of object that is being created. This is used - * internally for sanity checks on transactions. + * This creates a new instance of a class of binders which can be instantiated. This is called one + * time during library initialization and cleaned up when the process exits or execs. + * + * None of these parameters can be null. * - * None of these parameters can be nullptr. + * \param interfaceDescriptor this is a unique identifier for the class. This is used internally for + * sanity checks on transactions. + * \param onCreate see AIBinder_Class_onCreate. + * \param onDestroy see AIBinder_Class_onDestroy. + * \param onTransact see AIBinder_Class_onTransact. * - * This is created one time during library initialization and cleaned up when the process exits or - * execs. + * \return the class object representing these parameters or null on error. */ __attribute__((warn_unused_result)) AIBinder_Class* AIBinder_Class_define( const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate, @@ -174,12 +194,21 @@ __attribute__((warn_unused_result)) AIBinder_Class* AIBinder_Class_define( * hypothetical removeCallback function, the remote process would have no way to determine that * these two objects are actually equal using the AIBinder pointer alone (which they should be able * to do). Also see the suggested memory ownership model suggested above. + * + * \param clazz the type of the object to be created. + * \param args the args to pass to AIBinder_onCreate for that class. + * + * \return a binder object representing the newly instantiated object. */ __attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) __INTRODUCED_IN(29); /** * If this is hosted in a process other than the current one. + * + * \param binder the binder being queried. + * + * \return true if the AIBinder represents an object in another process. */ bool AIBinder_isRemote(const AIBinder* binder) __INTRODUCED_IN(29); @@ -189,13 +218,21 @@ bool AIBinder_isRemote(const AIBinder* binder) __INTRODUCED_IN(29); * this is automatically updated to reflect the current alive status of this binder. This will be * updated as the result of a transaction made using AIBinder_transact, but it will also be updated * based on the results of bookkeeping or other transactions made internally. + * + * \param binder the binder being queried. + * + * \return true if the binder is alive. */ bool AIBinder_isAlive(const AIBinder* binder) __INTRODUCED_IN(29); /** - * Built-in transaction for all binder objects. This sends a transaction which will immediately + * Built-in transaction for all binder objects. This sends a transaction that will immediately * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a * sanity check. + * + * \param binder the binder being queried. + * + * \return STATUS_OK if the ping succeeds. */ binder_status_t AIBinder_ping(AIBinder* binder) __INTRODUCED_IN(29); @@ -209,6 +246,12 @@ binder_status_t AIBinder_ping(AIBinder* binder) __INTRODUCED_IN(29); * identification and holding user data. * * If binder is local, this will return STATUS_INVALID_OPERATION. + * + * \param binder the binder object you want to receive death notifications from. + * \param recipient the callback that will receive notifications when/if the binder dies. + * \param cookie the value that will be passed to the death recipient on death. + * + * \return STATUS_OK on success. */ binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient, void* cookie) __INTRODUCED_IN(29); @@ -217,22 +260,62 @@ binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* * Stops registration for the associated binder dying. Does not delete the recipient. This function * may return a binder transaction failure and in case the death recipient cannot be found, it * returns STATUS_NAME_NOT_FOUND. + * + * \param binder the binder object to remove a previously linked death recipient from. + * \param recipient the callback to remove. + * \param cookie the cookie used to link to death. + * + * \return STATUS_OK on success. STATUS_NAME_NOT_FOUND if the binder cannot be found to be unlinked. */ binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient, void* cookie) __INTRODUCED_IN(29); /** + * This returns the calling UID assuming that this thread is called from a thread that is processing + * a binder transaction (for instance, in the implementation of AIBinder_Class_onTransact). + * + * This can be used with higher-level system services to determine the caller's identity and check + * permissions. + * + * \return calling uid or the current process's UID if this thread isn't processing a transaction. + */ +uid_t AIBinder_getCallingUid(); + +/** + * This returns the calling PID assuming that this thread is called from a thread that is processing + * a binder transaction (for instance, in the implementation of AIBinder_Class_onTransact). + * + * This can be used with higher-level system services to determine the caller's identity and check + * permissions. However, when doing this, one should be aware of possible TOCTOU problems when the + * calling process dies and is replaced with another process with elevated permissions and the same + * PID. + * + * \return calling pid or the current process's PID if this thread isn't processing a transaction. + * If the transaction being processed is a oneway transaction, then this method will return 0. + */ +pid_t AIBinder_getCallingPid(); + +/** * This can only be called if a strong reference to this object already exists in process. + * + * \param binder the binder object to add a refcount to. */ void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29); /** * This will delete the object and call onDestroy once the refcount reaches zero. + * + * \param binder the binder object to remove a refcount from. */ void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29); /** * For debugging only! + * + * \param binder the binder object to retrieve the refcount of. + * + * \return the number of strong-refs on this binder in this process. If binder is null, this will be + * -1. */ int32_t AIBinder_debugGetRefCount(AIBinder* binder) __INTRODUCED_IN(29); @@ -244,17 +327,32 @@ int32_t AIBinder_debugGetRefCount(AIBinder* binder) __INTRODUCED_IN(29); * * This returns true if the class association succeeds. If it fails, no change is made to the * binder object. + * + * \param binder the object to attach the class to. + * \param clazz the clazz to attach to binder. + * + * \return true if the binder has the class clazz and if the association was successful. */ bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) __INTRODUCED_IN(29); /** * Returns the class that this binder was constructed with or associated with. + * + * \param binder the object that is being queried. + * + * \return the class that this binder is associated with. If this binder wasn't created with + * AIBinder_new, and AIBinder_associateClass hasn't been called, then this will return null. */ const AIBinder_Class* AIBinder_getClass(AIBinder* binder) __INTRODUCED_IN(29); /** * Value returned by onCreate for a local binder. For stateless classes (if onCreate returns - * nullptr), this also returns nullptr. For a remote binder, this will always return nullptr. + * null), this also returns null. For a remote binder, this will always return null. + * + * \param binder the object that is being queried. + * + * \return the userdata returned from AIBinder_onCreate when this object was created. This may be + * null for stateless objects. For remote objects, this is always null. */ void* AIBinder_getUserData(AIBinder* binder) __INTRODUCED_IN(29); @@ -278,6 +376,12 @@ void* AIBinder_getUserData(AIBinder* binder) __INTRODUCED_IN(29); * ownership is passed to the caller. At this point, the parcel can be filled out and passed to * AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be * deleted with AParcel_delete. + * + * \param binder the binder object to start a transaction on. + * \param in out parameter for input data to the transaction. + * + * \return STATUS_OK on success. This will return STATUS_INVALID_OPERATION if the binder has not yet + * been associated with a class (see AIBinder_new and AIBinder_associateClass). */ binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) __INTRODUCED_IN(29); @@ -292,6 +396,16 @@ binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) __IN * * This does not affect the ownership of binder. The out parcel's ownership is passed to the caller * and must be released with AParcel_delete when finished reading. + * + * \param binder the binder object to transact on. + * \param code the implementation-specific code representing which transaction should be taken. + * \param in the implementation-specific input data to this transaction. + * \param out the implementation-specific output data to this transaction. + * \param flags possible flags to alter the way in which the transaction is conducted or 0. + * + * \return the result from the kernel or from the remote process. Usually, implementation-specific + * error codes are written to the output parcel, and the transaction code is reserved for kernel + * errors or error codes that have been repeated from subsequent transactions. */ binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in, AParcel** out, binder_flags_t flags) __INTRODUCED_IN(29); @@ -299,29 +413,45 @@ binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, APa /** * This does not take any ownership of the input binder, but it can be used to retrieve it if * something else in some process still holds a reference to it. + * + * \param binder object to create a weak pointer to. + * + * \return object representing a weak pointer to binder (or null if binder is null). */ __attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder) __INTRODUCED_IN(29); /** * Deletes the weak reference. This will have no impact on the lifetime of the binder. + * + * \param weakBinder object created with AIBinder_Weak_new. */ void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29); /** * If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns - * nullptr. + * null. + * + * \param weakBinder weak pointer to attempt retrieving the original object from. + * + * \return an AIBinder object with one refcount given to the caller or null. */ __attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29); /** * This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath. + * + * \param cookie the cookie passed to AIBinder_linkToDeath. */ typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29); /** * Creates a new binder death recipient. This can be attached to multiple different binder objects. + * + * \param onBinderDied the callback to call when this death recipient is invoked. + * + * \return the newly constructed object (or null if onBinderDied is null). */ __attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecipient_new( AIBinder_DeathRecipient_onBinderDied onBinderDied) __INTRODUCED_IN(29); @@ -329,10 +459,12 @@ __attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecip /** * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before * calling this as these will all be automatically unlinked. + * + * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new). */ void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29); -#endif //__ANDROID_API__ >= __ANDROID_API_Q__ +#endif //__ANDROID_API__ >= __ANDROID_API_Q__ __END_DECLS /** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h index 81fb3c5296..124f36c55b 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h @@ -39,6 +39,12 @@ __BEGIN_DECLS * If either env or the binder is null, null is returned. If this binder object was originally an * AIBinder object, the original object is returned. The returned object has one refcount * associated with it, and so this should be accompanied with an AIBinder_decStrong call. + * + * \param env Java environment. + * \param binder android.os.IBinder java object. + * + * \return an AIBinder object representing the Java binder object. If either parameter is null, or + * the Java object is of the wrong type, this will return null. */ __attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder) __INTRODUCED_IN(29); @@ -48,11 +54,16 @@ __attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* en * * If either env or the binder is null, null is returned. If this binder object was originally an * IBinder object, the original java object will be returned. + * + * \param env Java environment. + * \param binder the object to convert. + * + * \return an android.os.IBinder object or null if the parameters were null. */ __attribute__((warn_unused_result)) jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder) __INTRODUCED_IN(29); -#endif //__ANDROID_API__ >= __ANDROID_API_Q__ +#endif //__ANDROID_API__ >= __ANDROID_API_Q__ __END_DECLS /** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h index e37c388132..153272572f 100644 --- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h @@ -32,8 +32,6 @@ #include <assert.h> -#ifdef __cplusplus - #include <memory> #include <mutex> @@ -46,7 +44,7 @@ namespace ndk { * construct this object is with SharedRefBase::make. */ class SharedRefBase { -public: + public: SharedRefBase() {} virtual ~SharedRefBase() { std::call_once(mFlagThis, [&]() { @@ -83,7 +81,7 @@ public: return t->template ref<T>(); } -private: + private: std::once_flag mFlagThis; std::weak_ptr<SharedRefBase> mThis; }; @@ -92,7 +90,7 @@ private: * wrapper analog to IInterface */ class ICInterface : public SharedRefBase { -public: + public: ICInterface() {} virtual ~ICInterface() {} @@ -113,7 +111,7 @@ public: */ template <typename INTERFACE> class BnCInterface : public INTERFACE { -public: + public: BnCInterface() {} virtual ~BnCInterface() {} @@ -121,15 +119,15 @@ public: bool isRemote() override { return true; } -protected: + protected: /** * This function should only be called by asBinder. Otherwise, there is a possibility of * multiple AIBinder* objects being created for the same instance of an object. */ virtual SpAIBinder createBinder() = 0; -private: - std::mutex mMutex; // for asBinder + private: + std::mutex mMutex; // for asBinder ScopedAIBinder_Weak mWeakBinder; }; @@ -138,7 +136,7 @@ private: */ template <typename INTERFACE> class BpCInterface : public INTERFACE { -public: + public: BpCInterface(const SpAIBinder& binder) : mBinder(binder) {} virtual ~BpCInterface() {} @@ -146,7 +144,7 @@ public: bool isRemote() override { return AIBinder_isRemote(mBinder.get()); } -private: + private: SpAIBinder mBinder; }; @@ -171,8 +169,6 @@ SpAIBinder BpCInterface<INTERFACE>::asBinder() { return mBinder; } -} // namespace ndk - -#endif // __cplusplus +} // namespace ndk /** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h index d36b3c06f3..866af70157 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h @@ -47,120 +47,351 @@ typedef struct AParcel AParcel; /** * Cleans up a parcel. + * + * \param parcel A parcel returned by AIBinder_prepareTransaction or AIBinder_transact when a + * transaction is being aborted. */ void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29); /** - * This is called to allocate an array with a given length. If allocation fails, null should be - * returned. + * Sets the position within the parcel. + * + * \param parcel The parcel of which to set the position. + * \param position Position of the parcel to set. This must be a value returned by + * AParcel_getDataPosition. Positions are constant for a given parcel between processes. + * + * \return STATUS_OK on success. If position is negative, then STATUS_BAD_VALUE will be returned. */ -typedef void* (*AParcel_arrayReallocator)(void* vectorData, size_t length); +binder_status_t AParcel_setDataPosition(const AParcel* parcel, int32_t position) + __INTRODUCED_IN(29); + +/** + * Gets the current position within the parcel. + * + * \param parcel The parcel of which to get the position. + * + * \return The size of the parcel. This will always be greater than 0. The values returned by this + * function before and after calling various reads and writes are not defined. Only the delta + * between two positions between a specific sequence of calls is defined. For instance, if position + * is X, writeBool is called, and then position is Y, readBool can be called from position X will + * return the same value, and then position will be Y. + */ +int32_t AParcel_getDataPosition(const AParcel* parcel) __INTRODUCED_IN(29); + +/** + * This is called to allocate a buffer for a C-style string (null-terminated). The returned buffer + * should be at least length bytes. This includes space for a null terminator. For a string, length + * will always be strictly less than or equal to the maximum size that can be held in a size_t and + * will always be greater than 0. However, if a 'null' string is being read, length will be -1. + * + * See also AParcel_readString. + * + * If allocation fails, null should be returned. + * + * \param stringData some external representation of a string + * \param length the length of the buffer needed to fill (including the null-terminator) + * \param buffer a buffer of size 'length' or null if allocation failed. + * + * \return true if the allocation succeeded, false otherwise. If length is -1, a true return here + * means that a 'null' value (or equivalent) was successfully stored. + */ +typedef bool (*AParcel_stringAllocator)(void* stringData, int32_t length, char** buffer); + +/** + * This is called to allocate an array of size 'length'. If length is -1, then a 'null' array (or + * equivalent) should be created. + * + * See also AParcel_readStringArray + * + * \param arrayData some external representation of an array + * \param length the length to allocate this array to + * + * \return true if allocation succeeded. If length is -1, a true return here means that a 'null' + * value (or equivalent) was successfully stored. + */ +typedef bool (*AParcel_stringArrayAllocator)(void* arrayData, int32_t length); + +/** + * This is called to allocate a string inside of an array that was allocated by an + * AParcel_stringArrayAllocator. + * + * The index returned will always be within the range [0, length of arrayData). The returned buffer + * should be at least length bytes. This includes space for a null-terminator. For a string, length + * will always be strictly less than or equal to the maximum size that can be held in a size_t and + * will always be greater than 0. However, if a 'null' string is being read, length will be -1. + * + * See also AParcel_readStringArray + * + * \param arrayData some external representation of an array. + * \param index the index at which a string should be allocated. + * \param length the length of the string to be allocated at this index. See also + * AParcel_stringAllocator. This includes the length required for a null-terminator. + * \param buffer a buffer of size 'length' or null if allocation failed. + * + * \return true if the allocation succeeded, false otherwise. If length is -1, a true return here + * means that a 'null' value (or equivalent) was successfully stored. + */ +typedef bool (*AParcel_stringArrayElementAllocator)(void* arrayData, size_t index, int32_t length, + char** buffer); + +/** + * This returns the length and buffer of an array at a specific index in an arrayData object. + * + * See also AParcel_writeStringArray + * + * \param arrayData some external representation of an array. + * \param index the index at which a string should be allocated. + * \param outLength an out parameter for the length of the string at the specified index. This + * should not include the length for a null-terminator if there is one. If the object at this index + * is 'null', then this should be set to -1. + * + * \param a buffer of size outLength or more representing the string at the provided index. This is + * not required to be null-terminated. If the object at index is null, then this should be null. + */ +typedef const char* (*AParcel_stringArrayElementGetter)(const void* arrayData, size_t index, + size_t* outLength); // @START-PRIMITIVE-VECTOR-GETTERS /** * This is called to get the underlying data from an arrayData object. * - * This will never be called for an empty array. + * The implementation of this function should allocate a contiguous array of size 'length' and + * return that underlying buffer to be filled out. If there is an error or length is 0, null may be + * returned. If length is -1, this should allocate some representation of a null array. + * + * See also AParcel_readInt32Array + * + * \param arrayData some external representation of an array of int32_t. + * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of int32_t of size 'length' (if length is >= 0, if length is 0, this + * may be nullptr). + * + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef int32_t* (*AParcel_int32ArrayGetter)(void* arrayData); +typedef bool (*AParcel_int32ArrayAllocator)(void* arrayData, int32_t length, int32_t** outBuffer); /** * This is called to get the underlying data from an arrayData object. * - * This will never be called for an empty array. + * The implementation of this function should allocate a contiguous array of size 'length' and + * return that underlying buffer to be filled out. If there is an error or length is 0, null may be + * returned. If length is -1, this should allocate some representation of a null array. + * + * See also AParcel_readUint32Array + * + * \param arrayData some external representation of an array of uint32_t. + * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of uint32_t of size 'length' (if length is >= 0, if length is 0, this + * may be nullptr). + * + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef uint32_t* (*AParcel_uint32ArrayGetter)(void* arrayData); +typedef bool (*AParcel_uint32ArrayAllocator)(void* arrayData, int32_t length, uint32_t** outBuffer); /** * This is called to get the underlying data from an arrayData object. * - * This will never be called for an empty array. + * The implementation of this function should allocate a contiguous array of size 'length' and + * return that underlying buffer to be filled out. If there is an error or length is 0, null may be + * returned. If length is -1, this should allocate some representation of a null array. + * + * See also AParcel_readInt64Array + * + * \param arrayData some external representation of an array of int64_t. + * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of int64_t of size 'length' (if length is >= 0, if length is 0, this + * may be nullptr). + * + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef int64_t* (*AParcel_int64ArrayGetter)(void* arrayData); +typedef bool (*AParcel_int64ArrayAllocator)(void* arrayData, int32_t length, int64_t** outBuffer); /** * This is called to get the underlying data from an arrayData object. * - * This will never be called for an empty array. + * The implementation of this function should allocate a contiguous array of size 'length' and + * return that underlying buffer to be filled out. If there is an error or length is 0, null may be + * returned. If length is -1, this should allocate some representation of a null array. + * + * See also AParcel_readUint64Array + * + * \param arrayData some external representation of an array of uint64_t. + * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of uint64_t of size 'length' (if length is >= 0, if length is 0, this + * may be nullptr). + * + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef uint64_t* (*AParcel_uint64ArrayGetter)(void* arrayData); +typedef bool (*AParcel_uint64ArrayAllocator)(void* arrayData, int32_t length, uint64_t** outBuffer); /** * This is called to get the underlying data from an arrayData object. * - * This will never be called for an empty array. + * The implementation of this function should allocate a contiguous array of size 'length' and + * return that underlying buffer to be filled out. If there is an error or length is 0, null may be + * returned. If length is -1, this should allocate some representation of a null array. + * + * See also AParcel_readFloatArray + * + * \param arrayData some external representation of an array of float. + * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of float of size 'length' (if length is >= 0, if length is 0, this may + * be nullptr). + * + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef float* (*AParcel_floatArrayGetter)(void* arrayData); +typedef bool (*AParcel_floatArrayAllocator)(void* arrayData, int32_t length, float** outBuffer); /** * This is called to get the underlying data from an arrayData object. * - * This will never be called for an empty array. + * The implementation of this function should allocate a contiguous array of size 'length' and + * return that underlying buffer to be filled out. If there is an error or length is 0, null may be + * returned. If length is -1, this should allocate some representation of a null array. + * + * See also AParcel_readDoubleArray + * + * \param arrayData some external representation of an array of double. + * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of double of size 'length' (if length is >= 0, if length is 0, this may + * be nullptr). + * + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef double* (*AParcel_doubleArrayGetter)(void* arrayData); +typedef bool (*AParcel_doubleArrayAllocator)(void* arrayData, int32_t length, double** outBuffer); /** - * This is called to get the underlying data from an arrayData object. + * This allocates an array of size 'length' inside of arrayData and returns whether or not there was + * a success. If length is -1, then this should allocate some representation of a null array. + * + * See also AParcel_readBoolArray * - * This will never be called for an empty array. + * \param arrayData some external representation of an array of bool. + * \param length the length to allocate arrayData to (or -1 if this represents a null array). + * + * \return whether the allocation succeeded. + */ +typedef bool (*AParcel_boolArrayAllocator)(void* arrayData, int32_t length); + +/** + * This is called to get the underlying data from an arrayData object at index. + * + * See also AParcel_writeBoolArray + * + * \param arrayData some external representation of an array of bool. + * \param index the index of the value to be retrieved. + * + * \return the value of the array at index index. */ typedef bool (*AParcel_boolArrayGetter)(const void* arrayData, size_t index); /** * This is called to set an underlying value in an arrayData object at index. + * + * See also AParcel_readBoolArray + * + * \param arrayData some external representation of an array of bool. + * \param index the index of the value to be set. + * \param value the value to set at index index. */ typedef void (*AParcel_boolArraySetter)(void* arrayData, size_t index, bool value); /** * This is called to get the underlying data from an arrayData object. * - * This will never be called for an empty array. + * The implementation of this function should allocate a contiguous array of size 'length' and + * return that underlying buffer to be filled out. If there is an error or length is 0, null may be + * returned. If length is -1, this should allocate some representation of a null array. + * + * See also AParcel_readCharArray + * + * \param arrayData some external representation of an array of char16_t. + * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of char16_t of size 'length' (if length is >= 0, if length is 0, this + * may be nullptr). + * + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef char16_t* (*AParcel_charArrayGetter)(void* arrayData); +typedef bool (*AParcel_charArrayAllocator)(void* arrayData, int32_t length, char16_t** outBuffer); /** * This is called to get the underlying data from an arrayData object. * - * This will never be called for an empty array. + * The implementation of this function should allocate a contiguous array of size 'length' and + * return that underlying buffer to be filled out. If there is an error or length is 0, null may be + * returned. If length is -1, this should allocate some representation of a null array. + * + * See also AParcel_readByteArray + * + * \param arrayData some external representation of an array of int8_t. + * \param length the length to allocate arrayData to. + * \param outBuffer a buffer of int8_t of size 'length' (if length is >= 0, if length is 0, this may + * be nullptr). + * + * \return whether or not the allocation was successful (or whether a null array is represented when + * length is -1). */ -typedef int8_t* (*AParcel_byteArrayGetter)(void* arrayData); +typedef bool (*AParcel_byteArrayAllocator)(void* arrayData, int32_t length, int8_t** outBuffer); // @END-PRIMITIVE-VECTOR-GETTERS /** - * This is called to allocate a buffer + * Writes an AIBinder to the next location in a non-null parcel. Can be null. This does not take any + * refcounts of ownership of the binder from the client. * - * The length here includes the space required to insert a '\0' for a properly formed c-str. If the - * buffer returned from this function is retStr, it will be filled by AParcel_readString with the - * data from the remote process, and it will be filled such that retStr[length] == '\0'. + * \param parcel the parcel to write to. + * \param binder the value to write to the parcel. * - * If allocation fails, null should be returned. - */ -typedef void* (*AParcel_stringReallocator)(void* stringData, size_t length); - -/** - * This is called to get the buffer from a stringData object. - */ -typedef char* (*AParcel_stringGetter)(void* stringData); - -/** - * Writes an AIBinder to the next location in a non-null parcel. Can be null. + * \return STATUS_OK on successful write. */ binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) __INTRODUCED_IN(29); /** - * Reads an AIBinder from the next location in a non-null parcel. This will fail if the binder is - * non-null. One strong ref-count of ownership is passed to the caller of this function. + * Reads an AIBinder from the next location in a non-null parcel. One strong ref-count of ownership + * is passed to the caller of this function. + * + * \param parcel the parcel to read from. + * \param binder the out parameter for what is read from the parcel. This may be null. + * + * \return STATUS_OK on successful write. */ binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder) __INTRODUCED_IN(29); /** - * Reads an AIBinder from the next location in a non-null parcel. This may read a null. One strong - * ref-count of ownership is passed to the caller of this function. + * Writes a file descriptor to the next location in a non-null parcel. This does not take ownership + * of fd. + * + * This corresponds to the SDK's android.os.ParcelFileDescriptor. + * + * \param parcel the parcel to write to. + * \param fd the value to write to the parcel (-1 to represent a null ParcelFileDescriptor). + * + * \return STATUS_OK on successful write. */ -binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder) - __INTRODUCED_IN(29); +binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd); + +/** + * Reads an int from the next location in a non-null parcel. + * + * The returned fd must be closed. + * + * This corresponds to the SDK's android.os.ParcelFileDescriptor. + * + * \param parcel the parcel to read from. + * \param fd the out parameter for what is read from the parcel (or -1 to represent a null + * ParcelFileDescriptor) + * + * \return STATUS_OK on successful write. + */ +binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd); /** * Writes an AStatus object to the next location in a non-null parcel. @@ -170,6 +401,11 @@ binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder * status will be returned from this method and nothing will be written to the parcel. If either * this happens or if writing the status object itself fails, the return value from this function * should be propagated to the client, and AParcel_readStatusHeader shouldn't be called. + * + * \param parcel the parcel to write to. + * \param status the value to write to the parcel. + * + * \return STATUS_OK on successful write. */ binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status) __INTRODUCED_IN(29); @@ -177,243 +413,532 @@ binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status /** * Reads an AStatus from the next location in a non-null parcel. Ownership is passed to the caller * of this function. + * + * \param parcel the parcel to read from. + * \param status the out parameter for what is read from the parcel. + * + * \return STATUS_OK on successful write. */ binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status) __INTRODUCED_IN(29); /** - * Writes string value to the next location in a non-null parcel. + * Writes utf-8 string value to the next location in a non-null parcel. + * + * If length is -1, and string is nullptr, this will write a 'null' string to the parcel. + * + * \param parcel the parcel to write to. + * \param string the null-terminated string to write to the parcel, at least of size 'length'. + * \param length the length of the string to be written. + * + * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) +binder_status_t AParcel_writeString(AParcel* parcel, const char* string, int32_t length) __INTRODUCED_IN(29); /** - * Reads and allocates string value from the next location in a non-null parcel. + * Reads and allocates utf-8 string value from the next location in a non-null parcel. * - * Data is passed to the string allocator once the string size is known. This data should be used to - * point to some kind of string data. For instance, it could be a char*, and the string allocator - * could be realloc. Then the getter would simply be a cast to char*. In more complicated cases, - * stringData could be a structure containing additional string data. + * Data is passed to the string allocator once the string size is known. This size includes the + * space for the null-terminator of this string. This allocator returns a buffer which is used as + * the output buffer from this read. If there is a 'null' string on the binder buffer, the allocator + * will be called with length -1. * - * If this function returns a success, the buffer returned by allocator when passed stringData will - * contain a null-terminated c-str read from the binder. + * \param parcel the parcel to read from. + * \param stringData some external representation of a string. + * \param allocator allocator that will be called once the size of the string is known. + * + * \return STATUS_OK on successful write. + */ +binder_status_t AParcel_readString(const AParcel* parcel, void* stringData, + AParcel_stringAllocator allocator) __INTRODUCED_IN(29); + +/** + * Writes utf-8 string array data to the next location in a non-null parcel. + * + * length is the length of the array. AParcel_stringArrayElementGetter will be called for all + * indices in range [0, length) with the arrayData provided here. The string length and buffer + * returned from this function will be used to fill out the data from the parcel. If length is -1, + * this will write a 'null' string array to the binder buffer. + * + * \param parcel the parcel to write to. + * \param arrayData some external representation of an array. + * \param length the length of the array to be written. + * \param getter the callback that will be called for every index of the array to retrieve the + * corresponding string buffer. + * + * \return STATUS_OK on successful write. */ -binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringReallocator reallocator, - AParcel_stringGetter getter, void** stringData) +binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length, + AParcel_stringArrayElementGetter getter) + __INTRODUCED_IN(29); + +/** + * Reads and allocates utf-8 string array value from the next location in a non-null parcel. + * + * First, AParcel_stringArrayAllocator will be called with the size of the array to be read where + * length is the length of the array to be read from the parcel. Then, for each index i in [0, + * length), AParcel_stringArrayElementAllocator will be called with the length of the string to be + * read from the parcel. The resultant buffer from each of these calls will be filled according to + * the contents of the string that is read. If the string array being read is 'null', this will + * instead just pass -1 to AParcel_stringArrayAllocator. + * + * \param parcel the parcel to read from. + * \param arrayData some external representation of an array. + * \param allocator the callback that will be called with arrayData once the size of the output + * array is known. + * \param elementAllocator the callback that will be called on every index of arrayData to allocate + * the string at that location. + * + * \return STATUS_OK on successful read. + */ +binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData, + AParcel_stringArrayAllocator allocator, + AParcel_stringArrayElementAllocator elementAllocator) __INTRODUCED_IN(29); // @START-PRIMITIVE-READ-WRITE /** * Writes int32_t value to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param value the value to write to the parcel. + * + * \return STATUS_OK on successful write. */ binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) __INTRODUCED_IN(29); /** * Writes uint32_t value to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param value the value to write to the parcel. + * + * \return STATUS_OK on successful write. */ binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value) __INTRODUCED_IN(29); /** * Writes int64_t value to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param value the value to write to the parcel. + * + * \return STATUS_OK on successful write. */ binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) __INTRODUCED_IN(29); /** * Writes uint64_t value to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param value the value to write to the parcel. + * + * \return STATUS_OK on successful write. */ binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value) __INTRODUCED_IN(29); /** * Writes float value to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param value the value to write to the parcel. + * + * \return STATUS_OK on successful write. */ binder_status_t AParcel_writeFloat(AParcel* parcel, float value) __INTRODUCED_IN(29); /** * Writes double value to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param value the value to write to the parcel. + * + * \return STATUS_OK on successful write. */ binder_status_t AParcel_writeDouble(AParcel* parcel, double value) __INTRODUCED_IN(29); /** * Writes bool value to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param value the value to write to the parcel. + * + * \return STATUS_OK on successful write. */ binder_status_t AParcel_writeBool(AParcel* parcel, bool value) __INTRODUCED_IN(29); /** * Writes char16_t value to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param value the value to write to the parcel. + * + * \return STATUS_OK on successful write. */ binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value) __INTRODUCED_IN(29); /** * Writes int8_t value to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param value the value to write to the parcel. + * + * \return STATUS_OK on successful write. */ binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value) __INTRODUCED_IN(29); /** * Reads into int32_t value from the next location in a non-null parcel. + * + * \param parcel the parcel to read from. + * \param value the value to read from the parcel. + * + * \return STATUS_OK on successful read. */ binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) __INTRODUCED_IN(29); /** * Reads into uint32_t value from the next location in a non-null parcel. + * + * \param parcel the parcel to read from. + * \param value the value to read from the parcel. + * + * \return STATUS_OK on successful read. */ binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value) __INTRODUCED_IN(29); /** * Reads into int64_t value from the next location in a non-null parcel. + * + * \param parcel the parcel to read from. + * \param value the value to read from the parcel. + * + * \return STATUS_OK on successful read. */ binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) __INTRODUCED_IN(29); /** * Reads into uint64_t value from the next location in a non-null parcel. + * + * \param parcel the parcel to read from. + * \param value the value to read from the parcel. + * + * \return STATUS_OK on successful read. */ binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value) __INTRODUCED_IN(29); /** * Reads into float value from the next location in a non-null parcel. + * + * \param parcel the parcel to read from. + * \param value the value to read from the parcel. + * + * \return STATUS_OK on successful read. */ binder_status_t AParcel_readFloat(const AParcel* parcel, float* value) __INTRODUCED_IN(29); /** * Reads into double value from the next location in a non-null parcel. + * + * \param parcel the parcel to read from. + * \param value the value to read from the parcel. + * + * \return STATUS_OK on successful read. */ binder_status_t AParcel_readDouble(const AParcel* parcel, double* value) __INTRODUCED_IN(29); /** * Reads into bool value from the next location in a non-null parcel. + * + * \param parcel the parcel to read from. + * \param value the value to read from the parcel. + * + * \return STATUS_OK on successful read. */ binder_status_t AParcel_readBool(const AParcel* parcel, bool* value) __INTRODUCED_IN(29); /** * Reads into char16_t value from the next location in a non-null parcel. + * + * \param parcel the parcel to read from. + * \param value the value to read from the parcel. + * + * \return STATUS_OK on successful read. */ binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) __INTRODUCED_IN(29); /** * Reads into int8_t value from the next location in a non-null parcel. + * + * \param parcel the parcel to read from. + * \param value the value to read from the parcel. + * + * \return STATUS_OK on successful read. */ binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) __INTRODUCED_IN(29); /** * Writes an array of int32_t to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. + * + * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* value, size_t length) +binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of uint32_t to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. + * + * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* value, size_t length) +binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of int64_t to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. + * + * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* value, size_t length) +binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of uint64_t to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. + * + * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* value, size_t length) +binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of float to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. + * + * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* value, size_t length) +binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of double to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. + * + * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* value, size_t length) +binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of bool to the next location in a non-null parcel. + * + * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying + * values to write to the parcel. + * + * \param parcel the parcel to write to. + * \param arrayData some external representation of an array. + * \param length the length of arrayData (or -1 if this represents a null array). + * \param getter the callback to retrieve data at specific locations in the array. + * + * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, - AParcel_boolArrayGetter getter, size_t length) - __INTRODUCED_IN(29); +binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, int32_t length, + AParcel_boolArrayGetter getter) __INTRODUCED_IN(29); /** * Writes an array of char16_t to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. + * + * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* value, size_t length) +binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Writes an array of int8_t to the next location in a non-null parcel. + * + * \param parcel the parcel to write to. + * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0). + * \param length the length of arrayData or -1 if this represents a null array. + * + * \return STATUS_OK on successful write. */ -binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* value, size_t length) +binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, int32_t length) __INTRODUCED_IN(29); /** * Reads an array of int32_t from the next location in a non-null parcel. + * + * First, allocator will be called with the length of the array. If the allocation succeeds and the + * length is greater than zero, the buffer returned by the allocator will be filled with the + * corresponding data + * + * \param parcel the parcel to read from. + * \param arrayData some external representation of an array. + * \param allocator the callback that will be called to allocate the array. + * + * \return STATUS_OK on successful read. */ -binder_status_t AParcel_readInt32Array(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_int32ArrayGetter getter) __INTRODUCED_IN(29); +binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData, + AParcel_int32ArrayAllocator allocator) __INTRODUCED_IN(29); /** * Reads an array of uint32_t from the next location in a non-null parcel. + * + * First, allocator will be called with the length of the array. If the allocation succeeds and the + * length is greater than zero, the buffer returned by the allocator will be filled with the + * corresponding data + * + * \param parcel the parcel to read from. + * \param arrayData some external representation of an array. + * \param allocator the callback that will be called to allocate the array. + * + * \return STATUS_OK on successful read. */ -binder_status_t AParcel_readUint32Array(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_uint32ArrayGetter getter) __INTRODUCED_IN(29); +binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData, + AParcel_uint32ArrayAllocator allocator) __INTRODUCED_IN(29); /** * Reads an array of int64_t from the next location in a non-null parcel. + * + * First, allocator will be called with the length of the array. If the allocation succeeds and the + * length is greater than zero, the buffer returned by the allocator will be filled with the + * corresponding data + * + * \param parcel the parcel to read from. + * \param arrayData some external representation of an array. + * \param allocator the callback that will be called to allocate the array. + * + * \return STATUS_OK on successful read. */ -binder_status_t AParcel_readInt64Array(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_int64ArrayGetter getter) __INTRODUCED_IN(29); +binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData, + AParcel_int64ArrayAllocator allocator) __INTRODUCED_IN(29); /** * Reads an array of uint64_t from the next location in a non-null parcel. + * + * First, allocator will be called with the length of the array. If the allocation succeeds and the + * length is greater than zero, the buffer returned by the allocator will be filled with the + * corresponding data + * + * \param parcel the parcel to read from. + * \param arrayData some external representation of an array. + * \param allocator the callback that will be called to allocate the array. + * + * \return STATUS_OK on successful read. */ -binder_status_t AParcel_readUint64Array(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_uint64ArrayGetter getter) __INTRODUCED_IN(29); +binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData, + AParcel_uint64ArrayAllocator allocator) __INTRODUCED_IN(29); /** * Reads an array of float from the next location in a non-null parcel. + * + * First, allocator will be called with the length of the array. If the allocation succeeds and the + * length is greater than zero, the buffer returned by the allocator will be filled with the + * corresponding data + * + * \param parcel the parcel to read from. + * \param arrayData some external representation of an array. + * \param allocator the callback that will be called to allocate the array. + * + * \return STATUS_OK on successful read. */ -binder_status_t AParcel_readFloatArray(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_floatArrayGetter getter) __INTRODUCED_IN(29); +binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData, + AParcel_floatArrayAllocator allocator) __INTRODUCED_IN(29); /** * Reads an array of double from the next location in a non-null parcel. + * + * First, allocator will be called with the length of the array. If the allocation succeeds and the + * length is greater than zero, the buffer returned by the allocator will be filled with the + * corresponding data + * + * \param parcel the parcel to read from. + * \param arrayData some external representation of an array. + * \param allocator the callback that will be called to allocate the array. + * + * \return STATUS_OK on successful read. */ -binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_doubleArrayGetter getter) __INTRODUCED_IN(29); +binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData, + AParcel_doubleArrayAllocator allocator) __INTRODUCED_IN(29); /** * Reads an array of bool from the next location in a non-null parcel. + * + * First, allocator will be called with the length of the array. Then, for every i in [0, length), + * setter(arrayData, i, x) will be called where x is the value at the associated index. + * + * \param parcel the parcel to read from. + * \param arrayData some external representation of an array. + * \param allocator the callback that will be called to allocate the array. + * \param setter the callback that will be called to set a value at a specific location in the + * array. + * + * \return STATUS_OK on successful read. */ -binder_status_t AParcel_readBoolArray(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, +binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData, + AParcel_boolArrayAllocator allocator, AParcel_boolArraySetter setter) __INTRODUCED_IN(29); /** * Reads an array of char16_t from the next location in a non-null parcel. + * + * First, allocator will be called with the length of the array. If the allocation succeeds and the + * length is greater than zero, the buffer returned by the allocator will be filled with the + * corresponding data + * + * \param parcel the parcel to read from. + * \param arrayData some external representation of an array. + * \param allocator the callback that will be called to allocate the array. + * + * \return STATUS_OK on successful read. */ -binder_status_t AParcel_readCharArray(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_charArrayGetter getter) __INTRODUCED_IN(29); +binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData, + AParcel_charArrayAllocator allocator) __INTRODUCED_IN(29); /** * Reads an array of int8_t from the next location in a non-null parcel. + * + * First, allocator will be called with the length of the array. If the allocation succeeds and the + * length is greater than zero, the buffer returned by the allocator will be filled with the + * corresponding data + * + * \param parcel the parcel to read from. + * \param arrayData some external representation of an array. + * \param allocator the callback that will be called to allocate the array. + * + * \return STATUS_OK on successful read. */ -binder_status_t AParcel_readByteArray(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_byteArrayGetter getter) __INTRODUCED_IN(29); +binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData, + AParcel_byteArrayAllocator allocator) __INTRODUCED_IN(29); // @END-PRIMITIVE-READ-WRITE -#endif //__ANDROID_API__ >= __ANDROID_API_Q__ +#endif //__ANDROID_API__ >= __ANDROID_API_Q__ __END_DECLS /** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h index faeb78fdfa..f99c3a92e2 100644 --- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h +++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h @@ -26,34 +26,100 @@ #pragma once +#include <android/binder_auto_utils.h> #include <android/binder_parcel.h> -#ifdef __cplusplus - +#include <optional> #include <string> #include <vector> namespace ndk { /** - * This resizes a std::vector of some underlying type to the given length. + * This retrieves and allocates a vector to size 'length' and returns the underlying buffer. */ template <typename T> -static inline void* AParcel_stdVectorReallocator(void* vectorData, size_t length) { +static inline bool AParcel_stdVectorAllocator(void* vectorData, int32_t length, T** outBuffer) { + if (length < 0) return false; + std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData); - if (length > vec->max_size()) return nullptr; + if (length > vec->max_size()) return false; vec->resize(length); - return vec; + *outBuffer = vec->data(); + return true; } /** - * This retrieves the underlying contiguous vector from a corresponding vectorData. + * This retrieves and allocates a vector to size 'length' and returns the underlying buffer. */ template <typename T> -static inline T* AParcel_stdVectorGetter(void* vectorData) { +static inline bool AParcel_nullableStdVectorAllocator(void* vectorData, int32_t length, + T** outBuffer) { + std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData); + + if (length < 0) { + *vec = std::nullopt; + return true; + } + + *vec = std::optional<std::vector<T>>(std::vector<T>{}); + + if (length > (*vec)->max_size()) return false; + (*vec)->resize(length); + + *outBuffer = (*vec)->data(); + return true; +} + +/** + * This allocates a vector to size 'length' and returns whether the allocation is successful. + * + * See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined + * externally with respect to the NDK, and that size information is not passed into the NDK. + * Instead, it is used in cases where callbacks are used. Note that when this allocator is used, + * null arrays are not supported. + * + * See AParcel_readVector(const AParcel* parcel, std::vector<bool>) + * See AParcel_readVector(const AParcel* parcel, std::vector<std::string>) + */ +template <typename T> +static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, int32_t length) { + if (length < 0) return false; + std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData); - return vec->data(); + if (length > vec->max_size()) return false; + + vec->resize(length); + return true; +} + +/** + * This allocates a vector to size 'length' and returns whether the allocation is successful. + * + * See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined + * externally with respect to the NDK, and that size information is not passed into the NDK. + * Instead, it is used in cases where callbacks are used. Note, when this allocator is used, + * the vector itself can be nullable. + * + * See AParcel_readVector(const AParcel* parcel, + * std::optional<std::vector<std::optional<std::string>>>) + */ +template <typename T> +static inline bool AParcel_nullableStdVectorExternalAllocator(void* vectorData, int32_t length) { + std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData); + + if (length < 0) { + *vec = std::nullopt; + return true; + } + + *vec = std::optional<std::vector<T>>(std::vector<T>{}); + + if (length > (*vec)->max_size()) return false; + (*vec)->resize(length); + + return true; } /** @@ -77,229 +143,592 @@ static inline void AParcel_stdVectorSetter(void* vectorData, size_t index, T val } /** - * Writes a vector to the next location in a non-null parcel. + * This sets the underlying value in a corresponding vectorData which may not be contiguous at + * index. */ template <typename T> -static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<T>& vec); +static inline void AParcel_nullableStdVectorSetter(void* vectorData, size_t index, T value) { + std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData); + vec->value()[index] = value; +} /** - * Reads a vector to the next location in a non-null parcel. + * Convenience method to write a nullable strong binder. */ -template <typename T> -static inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<T>* vec); +static inline binder_status_t AParcel_writeNullableStrongBinder(AParcel* parcel, + const SpAIBinder& binder) { + return AParcel_writeStrongBinder(parcel, binder.get()); +} + +/** + * Convenience method to read a nullable strong binder. + */ +static inline binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, + SpAIBinder* binder) { + AIBinder* readBinder; + binder_status_t status = AParcel_readStrongBinder(parcel, &readBinder); + if (status == STATUS_OK) { + binder->set(readBinder); + } + return status; +} + +/** + * Convenience method to write a strong binder but return an error if it is null. + */ +static inline binder_status_t AParcel_writeRequiredStrongBinder(AParcel* parcel, + const SpAIBinder& binder) { + if (binder.get() == nullptr) { + return STATUS_UNEXPECTED_NULL; + } + return AParcel_writeStrongBinder(parcel, binder.get()); +} + +/** + * Convenience method to read a strong binder but return an error if it is null. + */ +static inline binder_status_t AParcel_readRequiredStrongBinder(const AParcel* parcel, + SpAIBinder* binder) { + AIBinder* readBinder; + binder_status_t ret = AParcel_readStrongBinder(parcel, &readBinder); + if (ret == STATUS_OK) { + if (readBinder == nullptr) { + return STATUS_UNEXPECTED_NULL; + } + + binder->set(readBinder); + } + return ret; +} + +/** + * Convenience method to write a ParcelFileDescriptor where -1 represents a null value. + */ +static inline binder_status_t AParcel_writeNullableParcelFileDescriptor( + AParcel* parcel, const ScopedFileDescriptor& fd) { + return AParcel_writeParcelFileDescriptor(parcel, fd.get()); +} + +/** + * Convenience method to read a ParcelFileDescriptor where -1 represents a null value. + */ +static inline binder_status_t AParcel_readNullableParcelFileDescriptor(const AParcel* parcel, + ScopedFileDescriptor* fd) { + int readFd; + binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd); + if (status == STATUS_OK) { + fd->set(readFd); + } + return status; +} + +/** + * Convenience method to write a valid ParcelFileDescriptor. + */ +static inline binder_status_t AParcel_writeRequiredParcelFileDescriptor( + AParcel* parcel, const ScopedFileDescriptor& fd) { + if (fd.get() < 0) { + return STATUS_UNEXPECTED_NULL; + } + return AParcel_writeParcelFileDescriptor(parcel, fd.get()); +} + +/** + * Convenience method to read a valid ParcelFileDescriptor. + */ +static inline binder_status_t AParcel_readRequiredParcelFileDescriptor(const AParcel* parcel, + ScopedFileDescriptor* fd) { + int readFd; + binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd); + if (status == STATUS_OK) { + if (readFd < 0) { + return STATUS_UNEXPECTED_NULL; + } + fd->set(readFd); + } + return status; +} + +/** + * Allocates a std::string to length and returns the underlying buffer. For use with + * AParcel_readString. See use below in AParcel_readString(const AParcel*, std::string*). + */ +static inline bool AParcel_stdStringAllocator(void* stringData, int32_t length, char** buffer) { + if (length <= 0) return false; + + std::string* str = static_cast<std::string*>(stringData); + str->resize(length - 1); + *buffer = &(*str)[0]; + return true; +} + +/** + * Allocates a string in a std::optional<std::string> to size 'length' (or to std::nullopt when + * length is -1) and returns the underlying buffer. For use with AParcel_readString. See use below + * in AParcel_readString(const AParcel*, std::optional<std::string>*). + */ +static inline bool AParcel_nullableStdStringAllocator(void* stringData, int32_t length, + char** buffer) { + if (length == 0) return false; + + std::optional<std::string>* str = static_cast<std::optional<std::string>*>(stringData); + + if (length < 0) { + *str = std::nullopt; + return true; + } + + *str = std::optional<std::string>(std::string{}); + (*str)->resize(length - 1); + *buffer = &(**str)[0]; + return true; +} + +/** + * Allocates a std::string inside of a std::vector<std::string> at index 'index' to size 'length'. + */ +static inline bool AParcel_stdVectorStringElementAllocator(void* vectorData, size_t index, + int32_t length, char** buffer) { + std::vector<std::string>* vec = static_cast<std::vector<std::string>*>(vectorData); + std::string& element = vec->at(index); + return AParcel_stdStringAllocator(static_cast<void*>(&element), length, buffer); +} + +/** + * This gets the length and buffer of a std::string inside of a std::vector<std::string> at index + * index. + */ +static inline const char* AParcel_stdVectorStringElementGetter(const void* vectorData, size_t index, + size_t* outLength) { + const std::vector<std::string>* vec = static_cast<const std::vector<std::string>*>(vectorData); + const std::string& element = vec->at(index); + + *outLength = element.size(); + return element.c_str(); +} + +/** + * Allocates a string in a std::optional<std::string> inside of a + * std::optional<std::vector<std::optional<std::string>>> at index 'index' to size 'length' (or to + * std::nullopt when length is -1). + */ +static inline bool AParcel_nullableStdVectorStringElementAllocator(void* vectorData, size_t index, + int32_t length, char** buffer) { + std::optional<std::vector<std::optional<std::string>>>* vec = + static_cast<std::optional<std::vector<std::optional<std::string>>>*>(vectorData); + std::optional<std::string>& element = vec->value().at(index); + return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer); +} + +/** + * This gets the length and buffer of a std::optional<std::string> inside of a + * std::vector<std::string> at index index. If the string is null, then it returns null and a length + * of -1. + */ +static inline const char* AParcel_nullableStdVectorStringElementGetter(const void* vectorData, + size_t index, + size_t* outLength) { + const std::optional<std::vector<std::optional<std::string>>>* vec = + static_cast<const std::optional<std::vector<std::optional<std::string>>>*>(vectorData); + const std::optional<std::string>& element = vec->value().at(index); + + if (!element) { + *outLength = -1; + return nullptr; + } + + *outLength = element->size(); + return element->c_str(); +} + +/** + * Convenience API for writing a std::string. + */ +static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) { + return AParcel_writeString(parcel, str.c_str(), str.size()); +} + +/** + * Convenience API for reading a std::string. + */ +static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) { + void* stringData = static_cast<void*>(str); + return AParcel_readString(parcel, stringData, AParcel_stdStringAllocator); +} + +/** + * Convenience API for writing a std::optional<std::string>. + */ +static inline binder_status_t AParcel_writeString(AParcel* parcel, + const std::optional<std::string>& str) { + if (!str) { + return AParcel_writeString(parcel, nullptr, -1); + } + + return AParcel_writeString(parcel, str->c_str(), str->size()); +} + +/** + * Convenience API for reading a std::optional<std::string>. + */ +static inline binder_status_t AParcel_readString(const AParcel* parcel, + std::optional<std::string>* str) { + void* stringData = static_cast<void*>(str); + return AParcel_readString(parcel, stringData, AParcel_nullableStdStringAllocator); +} + +/** + * Convenience API for writing a std::vector<std::string> + */ +static inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::vector<std::string>& vec) { + const void* vectorData = static_cast<const void*>(&vec); + return AParcel_writeStringArray(parcel, vectorData, vec.size(), + AParcel_stdVectorStringElementGetter); +} + +/** + * Convenience API for reading a std::vector<std::string> + */ +static inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::vector<std::string>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readStringArray(parcel, vectorData, + AParcel_stdVectorExternalAllocator<std::string>, + AParcel_stdVectorStringElementAllocator); +} + +/** + * Convenience API for writing a std::optional<std::vector<std::optional<std::string>>> + */ +static inline binder_status_t AParcel_writeVector( + AParcel* parcel, const std::optional<std::vector<std::optional<std::string>>>& vec) { + const void* vectorData = static_cast<const void*>(&vec); + return AParcel_writeStringArray(parcel, vectorData, (vec ? vec->size() : -1), + AParcel_nullableStdVectorStringElementGetter); +} + +/** + * Convenience API for reading a std::optional<std::vector<std::optional<std::string>>> + */ +static inline binder_status_t AParcel_readVector( + const AParcel* parcel, std::optional<std::vector<std::optional<std::string>>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readStringArray( + parcel, vectorData, + AParcel_nullableStdVectorExternalAllocator<std::optional<std::string>>, + AParcel_nullableStdVectorStringElementAllocator); +} // @START /** * Writes a vector of int32_t to the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_writeVector<int32_t>(AParcel* parcel, - const std::vector<int32_t>& vec) { +inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) { return AParcel_writeInt32Array(parcel, vec.data(), vec.size()); } /** + * Writes an optional vector of int32_t to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<int32_t>>& vec) { + if (!vec) return AParcel_writeInt32Array(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of int32_t from the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_readVector<int32_t>(const AParcel* parcel, - std::vector<int32_t>* vec) { +inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int32_t>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>); +} + +/** + * Reads an optional vector of int32_t from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<int32_t>>* vec) { void* vectorData = static_cast<void*>(vec); - return AParcel_readInt32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int32_t>, - AParcel_stdVectorGetter<int32_t>); + return AParcel_readInt32Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int32_t>); } /** * Writes a vector of uint32_t to the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_writeVector<uint32_t>(AParcel* parcel, - const std::vector<uint32_t>& vec) { +inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) { return AParcel_writeUint32Array(parcel, vec.data(), vec.size()); } /** + * Writes an optional vector of uint32_t to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<uint32_t>>& vec) { + if (!vec) return AParcel_writeUint32Array(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of uint32_t from the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_readVector<uint32_t>(const AParcel* parcel, - std::vector<uint32_t>* vec) { +inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint32_t>* vec) { void* vectorData = static_cast<void*>(vec); - return AParcel_readUint32Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint32_t>, - AParcel_stdVectorGetter<uint32_t>); + return AParcel_readUint32Array(parcel, vectorData, AParcel_stdVectorAllocator<uint32_t>); +} + +/** + * Reads an optional vector of uint32_t from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<uint32_t>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readUint32Array(parcel, vectorData, + AParcel_nullableStdVectorAllocator<uint32_t>); } /** * Writes a vector of int64_t to the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_writeVector<int64_t>(AParcel* parcel, - const std::vector<int64_t>& vec) { +inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) { return AParcel_writeInt64Array(parcel, vec.data(), vec.size()); } /** + * Writes an optional vector of int64_t to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<int64_t>>& vec) { + if (!vec) return AParcel_writeInt64Array(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of int64_t from the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_readVector<int64_t>(const AParcel* parcel, - std::vector<int64_t>* vec) { +inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int64_t>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>); +} + +/** + * Reads an optional vector of int64_t from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<int64_t>>* vec) { void* vectorData = static_cast<void*>(vec); - return AParcel_readInt64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<int64_t>, - AParcel_stdVectorGetter<int64_t>); + return AParcel_readInt64Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int64_t>); } /** * Writes a vector of uint64_t to the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_writeVector<uint64_t>(AParcel* parcel, - const std::vector<uint64_t>& vec) { +inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) { return AParcel_writeUint64Array(parcel, vec.data(), vec.size()); } /** + * Writes an optional vector of uint64_t to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<uint64_t>>& vec) { + if (!vec) return AParcel_writeUint64Array(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of uint64_t from the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_readVector<uint64_t>(const AParcel* parcel, - std::vector<uint64_t>* vec) { +inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint64_t>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readUint64Array(parcel, vectorData, AParcel_stdVectorAllocator<uint64_t>); +} + +/** + * Reads an optional vector of uint64_t from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<uint64_t>>* vec) { void* vectorData = static_cast<void*>(vec); - return AParcel_readUint64Array(parcel, &vectorData, &AParcel_stdVectorReallocator<uint64_t>, - AParcel_stdVectorGetter<uint64_t>); + return AParcel_readUint64Array(parcel, vectorData, + AParcel_nullableStdVectorAllocator<uint64_t>); } /** * Writes a vector of float to the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_writeVector<float>(AParcel* parcel, const std::vector<float>& vec) { +inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) { return AParcel_writeFloatArray(parcel, vec.data(), vec.size()); } /** + * Writes an optional vector of float to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<float>>& vec) { + if (!vec) return AParcel_writeFloatArray(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of float from the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_readVector<float>(const AParcel* parcel, std::vector<float>* vec) { +inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<float>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readFloatArray(parcel, vectorData, AParcel_stdVectorAllocator<float>); +} + +/** + * Reads an optional vector of float from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<float>>* vec) { void* vectorData = static_cast<void*>(vec); - return AParcel_readFloatArray(parcel, &vectorData, &AParcel_stdVectorReallocator<float>, - AParcel_stdVectorGetter<float>); + return AParcel_readFloatArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<float>); } /** * Writes a vector of double to the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_writeVector<double>(AParcel* parcel, - const std::vector<double>& vec) { +inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) { return AParcel_writeDoubleArray(parcel, vec.data(), vec.size()); } /** + * Writes an optional vector of double to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<double>>& vec) { + if (!vec) return AParcel_writeDoubleArray(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); +} + +/** * Reads a vector of double from the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_readVector<double>(const AParcel* parcel, std::vector<double>* vec) { +inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<double>* vec) { void* vectorData = static_cast<void*>(vec); - return AParcel_readDoubleArray(parcel, &vectorData, &AParcel_stdVectorReallocator<double>, - AParcel_stdVectorGetter<double>); + return AParcel_readDoubleArray(parcel, vectorData, AParcel_stdVectorAllocator<double>); +} + +/** + * Reads an optional vector of double from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<double>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readDoubleArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<double>); } /** * Writes a vector of bool to the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_writeVector<bool>(AParcel* parcel, const std::vector<bool>& vec) { - return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), - AParcel_stdVectorGetter<bool>, vec.size()); +inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) { + return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), vec.size(), + AParcel_stdVectorGetter<bool>); +} + +/** + * Writes an optional vector of bool to the next location in a non-null parcel. + */ +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<bool>>& vec) { + if (!vec) return AParcel_writeBoolArray(parcel, nullptr, -1, AParcel_stdVectorGetter<bool>); + return AParcel_writeVector(parcel, *vec); } /** * Reads a vector of bool from the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_readVector<bool>(const AParcel* parcel, std::vector<bool>* vec) { +inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<bool>* vec) { void* vectorData = static_cast<void*>(vec); - return AParcel_readBoolArray(parcel, &vectorData, &AParcel_stdVectorReallocator<bool>, + return AParcel_readBoolArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<bool>, AParcel_stdVectorSetter<bool>); } /** + * Reads an optional vector of bool from the next location in a non-null parcel. + */ +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<bool>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readBoolArray(parcel, vectorData, + AParcel_nullableStdVectorExternalAllocator<bool>, + AParcel_nullableStdVectorSetter<bool>); +} + +/** * Writes a vector of char16_t to the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_writeVector<char16_t>(AParcel* parcel, - const std::vector<char16_t>& vec) { +inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) { return AParcel_writeCharArray(parcel, vec.data(), vec.size()); } /** - * Reads a vector of char16_t from the next location in a non-null parcel. + * Writes an optional vector of char16_t to the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_readVector<char16_t>(const AParcel* parcel, - std::vector<char16_t>* vec) { - void* vectorData = static_cast<void*>(vec); - return AParcel_readCharArray(parcel, &vectorData, &AParcel_stdVectorReallocator<char16_t>, - AParcel_stdVectorGetter<char16_t>); +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<char16_t>>& vec) { + if (!vec) return AParcel_writeCharArray(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); } /** - * Writes a vector of int8_t to the next location in a non-null parcel. + * Reads a vector of char16_t from the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_writeVector<int8_t>(AParcel* parcel, - const std::vector<int8_t>& vec) { - return AParcel_writeByteArray(parcel, vec.data(), vec.size()); +inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<char16_t>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readCharArray(parcel, vectorData, AParcel_stdVectorAllocator<char16_t>); } /** - * Reads a vector of int8_t from the next location in a non-null parcel. + * Reads an optional vector of char16_t from the next location in a non-null parcel. */ -template <> -inline binder_status_t AParcel_readVector<int8_t>(const AParcel* parcel, std::vector<int8_t>* vec) { +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<char16_t>>* vec) { void* vectorData = static_cast<void*>(vec); - return AParcel_readByteArray(parcel, &vectorData, &AParcel_stdVectorReallocator<int8_t>, - AParcel_stdVectorGetter<int8_t>); + return AParcel_readCharArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<char16_t>); } -// @END - /** - * Takes a std::string and reallocates it to the specified length. For use with AParcel_readString. - * See use below in AParcel_readString. + * Writes a vector of int8_t to the next location in a non-null parcel. */ -static inline void* AParcel_stdStringReallocator(void* stringData, size_t length) { - std::string* str = static_cast<std::string*>(stringData); - str->resize(length - 1); - return stringData; +inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int8_t>& vec) { + return AParcel_writeByteArray(parcel, vec.data(), vec.size()); } /** - * Takes a std::string and returns the inner char*. + * Writes an optional vector of int8_t to the next location in a non-null parcel. */ -static inline char* AParcel_stdStringGetter(void* stringData) { - std::string* str = static_cast<std::string*>(stringData); - return &(*str)[0]; +inline binder_status_t AParcel_writeVector(AParcel* parcel, + const std::optional<std::vector<int8_t>>& vec) { + if (!vec) return AParcel_writeByteArray(parcel, nullptr, -1); + return AParcel_writeVector(parcel, *vec); } /** - * Convenience API for writing a std::string. + * Reads a vector of int8_t from the next location in a non-null parcel. */ -static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) { - return AParcel_writeString(parcel, str.c_str(), str.size()); +inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int8_t>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>); } /** - * Convenience API for reading a std::string. + * Reads an optional vector of int8_t from the next location in a non-null parcel. */ -static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) { - void* stringData = static_cast<void*>(str); - return AParcel_readString(parcel, AParcel_stdStringReallocator, AParcel_stdStringGetter, - &stringData); +inline binder_status_t AParcel_readVector(const AParcel* parcel, + std::optional<std::vector<int8_t>>* vec) { + void* vectorData = static_cast<void*>(vec); + return AParcel_readByteArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<int8_t>); } +// @END + +/** + * Convenience API for writing the size of a vector. + */ template <typename T> static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, const std::vector<T>& vec) { if (vec.size() > INT32_MAX) { @@ -309,6 +738,26 @@ static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, const std return AParcel_writeInt32(parcel, static_cast<int32_t>(vec.size())); } +/** + * Convenience API for writing the size of a vector. + */ +template <typename T> +static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, + const std::optional<std::vector<T>>& vec) { + if (!vec) { + return AParcel_writeInt32(parcel, -1); + } + + if (vec->size() > INT32_MAX) { + return STATUS_BAD_VALUE; + } + + return AParcel_writeInt32(parcel, static_cast<int32_t>(vec->size())); +} + +/** + * Convenience API for resizing a vector. + */ template <typename T> static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, std::vector<T>* vec) { int32_t size; @@ -321,8 +770,28 @@ static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, std::v return STATUS_OK; } -} // namespace ndk +/** + * Convenience API for resizing a vector. + */ +template <typename T> +static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, + std::optional<std::vector<T>>* vec) { + int32_t size; + binder_status_t err = AParcel_readInt32(parcel, &size); + + if (err != STATUS_OK) return err; + if (size < -1) return STATUS_UNEXPECTED_NULL; + + if (size == -1) { + *vec = std::nullopt; + return STATUS_OK; + } + + *vec = std::optional<std::vector<T>>(std::vector<T>{}); + (*vec)->resize(static_cast<size_t>(size)); + return STATUS_OK; +} -#endif // __cplusplus +} // namespace ndk /** @} */ diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h index 2d8b7fa095..2671b9b6fc 100644 --- a/libs/binder/ndk/include_ndk/android/binder_status.h +++ b/libs/binder/ndk/include_ndk/android/binder_status.h @@ -35,7 +35,7 @@ __BEGIN_DECLS enum { STATUS_OK = 0, - STATUS_UNKNOWN_ERROR = (-2147483647 - 1), // INT32_MIN value + STATUS_UNKNOWN_ERROR = (-2147483647 - 1), // INT32_MIN value STATUS_NO_MEMORY = -ENOMEM, STATUS_INVALID_OPERATION = -ENOSYS, STATUS_BAD_VALUE = -EINVAL, @@ -95,24 +95,39 @@ typedef int32_t binder_exception_t; * along with service specific errors. * * It is not required to be used in order to parcel/receive transactions, but it is required in - * order to be compatible with standard AIDL transactions. + * order to be compatible with standard AIDL transactions since it is written as the header to the + * out parcel for transactions which get executed (don't fail during unparceling of input arguments + * or sooner). */ struct AStatus; typedef struct AStatus AStatus; /** * New status which is considered a success. + * + * \return a newly constructed status object that the caller owns. */ __attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29); /** * New status with exception code. + * + * \param exception the code that this status should represent. If this is EX_NONE, then this + * constructs an non-error status object. + * + * \return a newly constructed status object that the caller owns. */ __attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCode(binder_exception_t exception) __INTRODUCED_IN(29); /** * New status with exception code and message. + * + * \param exception the code that this status should represent. If this is EX_NONE, then this + * constructs an non-error status object. + * \param message the error message to associate with this status object. + * + * \return a newly constructed status object that the caller owns. */ __attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCodeWithMessage( binder_exception_t exception, const char* message) __INTRODUCED_IN(29); @@ -121,6 +136,10 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCodeWithMessag * New status with a service speciic error. * * This is considered to be EX_TRANSACTION_FAILED with extra information. + * + * \param serviceSpecific an implementation defined error code. + * + * \return a newly constructed status object that the caller owns. */ __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificError( int32_t serviceSpecific) __INTRODUCED_IN(29); @@ -129,6 +148,11 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificError( * New status with a service specific error and message. * * This is considered to be EX_TRANSACTION_FAILED with extra information. + * + * \param serviceSpecific an implementation defined error code. + * \param message the error message to associate with this status object. + * + * \return a newly constructed status object that the caller owns. */ __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificErrorWithMessage( int32_t serviceSpecific, const char* message) __INTRODUCED_IN(29); @@ -137,6 +161,10 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificErrorWit * New status with binder_status_t. This is typically for low level failures when a binder_status_t * is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning * an AStatus instance. + * + * \param a low-level error to associate with this status object. + * + * \return a newly constructed status object that the caller owns. */ __attribute__((warn_unused_result)) AStatus* AStatus_fromStatus(binder_status_t status) __INTRODUCED_IN(29); @@ -144,11 +172,19 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromStatus(binder_status_t /** * Whether this object represents a successful transaction. If this function returns true, then * AStatus_getExceptionCode will return EX_NONE. + * + * \param status the status being queried. + * + * \return whether the status represents a successful transaction. For more details, see below. */ bool AStatus_isOk(const AStatus* status) __INTRODUCED_IN(29); /** * The exception that this status object represents. + * + * \param status the status being queried. + * + * \return the exception code that this object represents. */ binder_exception_t AStatus_getExceptionCode(const AStatus* status) __INTRODUCED_IN(29); @@ -157,6 +193,10 @@ binder_exception_t AStatus_getExceptionCode(const AStatus* status) __INTRODUCED_ * non-zero result if AStatus_getExceptionCode returns EX_SERVICE_SPECIFIC. If this function returns * 0, the status object may still represent a different exception or status. To find out if this * transaction as a whole is okay, use AStatus_isOk instead. + * + * \param status the status being queried. + * + * \return the service-specific error code if the exception code is EX_SERVICE_SPECIFIC or 0. */ int32_t AStatus_getServiceSpecificError(const AStatus* status) __INTRODUCED_IN(29); @@ -165,6 +205,10 @@ int32_t AStatus_getServiceSpecificError(const AStatus* status) __INTRODUCED_IN(2 * if AStatus_getExceptionCode returns EX_TRANSACTION_FAILED. If this function return 0, the status * object may represent a different exception or a service specific error. To find out if this * transaction as a whole is okay, use AStatus_isOk instead. + * + * \param status the status being queried. + * + * \return the status code if the exception code is EX_TRANSACTION_FAILED or 0. */ binder_status_t AStatus_getStatus(const AStatus* status) __INTRODUCED_IN(29); @@ -173,15 +217,21 @@ binder_status_t AStatus_getStatus(const AStatus* status) __INTRODUCED_IN(29); * message, this will return an empty string. * * The returned string has the lifetime of the status object passed into this function. + * + * \param status the status being queried. + * + * \return the message associated with this error. */ const char* AStatus_getMessage(const AStatus* status) __INTRODUCED_IN(29); /** * Deletes memory associated with the status instance. + * + * \param status the status to delete, returned from AStatus_newOk or one of the AStatus_from* APIs. */ void AStatus_delete(AStatus* status) __INTRODUCED_IN(29); -#endif //__ANDROID_API__ >= __ANDROID_API_Q__ +#endif //__ANDROID_API__ >= __ANDROID_API_Q__ __END_DECLS /** @} */ diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index f84814fa3c..4328b6ea6d 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -7,6 +7,8 @@ LIBBINDER_NDK { # introduced=29 AIBinder_debugGetRefCount; AIBinder_decStrong; AIBinder_fromJavaBinder; + AIBinder_getCallingPid; + AIBinder_getCallingUid; AIBinder_getClass; AIBinder_getUserData; AIBinder_incStrong; @@ -23,6 +25,7 @@ LIBBINDER_NDK { # introduced=29 AIBinder_Weak_new; AIBinder_Weak_promote; AParcel_delete; + AParcel_getDataPosition; AParcel_readBool; AParcel_readBoolArray; AParcel_readByte; @@ -37,14 +40,16 @@ LIBBINDER_NDK { # introduced=29 AParcel_readInt32Array; AParcel_readInt64; AParcel_readInt64Array; - AParcel_readNullableStrongBinder; + AParcel_readParcelFileDescriptor; AParcel_readStatusHeader; AParcel_readString; + AParcel_readStringArray; AParcel_readStrongBinder; AParcel_readUint32; AParcel_readUint32Array; AParcel_readUint64; AParcel_readUint64Array; + AParcel_setDataPosition; AParcel_writeBool; AParcel_writeBoolArray; AParcel_writeByte; @@ -59,8 +64,10 @@ LIBBINDER_NDK { # introduced=29 AParcel_writeInt32Array; AParcel_writeInt64; AParcel_writeInt64Array; + AParcel_writeParcelFileDescriptor; AParcel_writeStatusHeader; AParcel_writeString; + AParcel_writeStringArray; AParcel_writeStrongBinder; AParcel_writeUint32; AParcel_writeUint32Array; diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index 29094dba7b..2d68559395 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -23,34 +23,59 @@ #include <limits> #include <android-base/logging.h> +#include <android-base/unique_fd.h> #include <binder/Parcel.h> +#include <binder/ParcelFileDescriptor.h> #include <utils/Unicode.h> using ::android::IBinder; using ::android::Parcel; using ::android::sp; using ::android::status_t; +using ::android::base::unique_fd; +using ::android::os::ParcelFileDescriptor; template <typename T> -using ContiguousArrayGetter = T* (*)(void* arrayData); +using ContiguousArrayAllocator = bool (*)(void* arrayData, int32_t length, T** outBuffer); + +template <typename T> +using ArrayAllocator = bool (*)(void* arrayData, int32_t length); template <typename T> using ArrayGetter = T (*)(const void* arrayData, size_t index); template <typename T> using ArraySetter = void (*)(void* arrayData, size_t index, T value); -template <typename T> -binder_status_t WriteArray(AParcel* parcel, const T* array, size_t length) { - if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE; +binder_status_t WriteAndValidateArraySize(AParcel* parcel, bool isNullArray, int32_t length) { + // only -1 can be used to represent a null array + if (length < -1) return STATUS_BAD_VALUE; + + if (!isNullArray && length < 0) { + LOG(ERROR) << __func__ << ": null array must be used with length == -1."; + return STATUS_BAD_VALUE; + } + if (isNullArray && length > 0) { + LOG(ERROR) << __func__ << ": null buffer cannot be for size " << length << " array."; + return STATUS_BAD_VALUE; + } Parcel* rawParcel = parcel->get(); status_t status = rawParcel->writeInt32(static_cast<int32_t>(length)); if (status != STATUS_OK) return PruneStatusT(status); + return STATUS_OK; +} + +template <typename T> +binder_status_t WriteArray(AParcel* parcel, const T* array, int32_t length) { + binder_status_t status = WriteAndValidateArraySize(parcel, array == nullptr, length); + if (status != STATUS_OK) return status; + if (length <= 0) return STATUS_OK; + int32_t size = 0; if (__builtin_smul_overflow(sizeof(T), length, &size)) return STATUS_NO_MEMORY; - void* const data = rawParcel->writeInplace(size); + void* const data = parcel->get()->writeInplace(size); if (data == nullptr) return STATUS_NO_MEMORY; memcpy(data, array, size); @@ -60,17 +85,16 @@ binder_status_t WriteArray(AParcel* parcel, const T* array, size_t length) { // Each element in a char16_t array is converted to an int32_t (not packed). template <> -binder_status_t WriteArray<char16_t>(AParcel* parcel, const char16_t* array, size_t length) { - if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE; - - Parcel* rawParcel = parcel->get(); - - status_t status = rawParcel->writeInt32(static_cast<int32_t>(length)); - if (status != STATUS_OK) return PruneStatusT(status); +binder_status_t WriteArray<char16_t>(AParcel* parcel, const char16_t* array, int32_t length) { + binder_status_t status = WriteAndValidateArraySize(parcel, array == nullptr, length); + if (status != STATUS_OK) return status; + if (length <= 0) return STATUS_OK; int32_t size = 0; if (__builtin_smul_overflow(sizeof(char16_t), length, &size)) return STATUS_NO_MEMORY; + Parcel* rawParcel = parcel->get(); + for (int32_t i = 0; i < length; i++) { status = rawParcel->writeChar(array[i]); @@ -81,22 +105,20 @@ binder_status_t WriteArray<char16_t>(AParcel* parcel, const char16_t* array, siz } template <typename T> -binder_status_t ReadArray(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, ContiguousArrayGetter<T> getter) { +binder_status_t ReadArray(const AParcel* parcel, void* arrayData, + ContiguousArrayAllocator<T> allocator) { const Parcel* rawParcel = parcel->get(); int32_t length; status_t status = rawParcel->readInt32(&length); if (status != STATUS_OK) return PruneStatusT(status); - if (length < 0) return STATUS_UNEXPECTED_NULL; - - *arrayData = reallocator(*arrayData, length); - if (*arrayData == nullptr) return STATUS_NO_MEMORY; + if (length < -1) return STATUS_BAD_VALUE; - if (length == 0) return STATUS_OK; + T* array; + if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY; - T* array = getter(*arrayData); + if (length <= 0) return STATUS_OK; if (array == nullptr) return STATUS_NO_MEMORY; int32_t size = 0; @@ -112,23 +134,20 @@ binder_status_t ReadArray(const AParcel* parcel, void** arrayData, // Each element in a char16_t array is converted to an int32_t (not packed) template <> -binder_status_t ReadArray<char16_t>(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - ContiguousArrayGetter<char16_t> getter) { +binder_status_t ReadArray<char16_t>(const AParcel* parcel, void* arrayData, + ContiguousArrayAllocator<char16_t> allocator) { const Parcel* rawParcel = parcel->get(); int32_t length; status_t status = rawParcel->readInt32(&length); if (status != STATUS_OK) return PruneStatusT(status); - if (length < 0) return STATUS_UNEXPECTED_NULL; + if (length < -1) return STATUS_BAD_VALUE; - *arrayData = reallocator(*arrayData, length); - if (*arrayData == nullptr) return STATUS_NO_MEMORY; + char16_t* array; + if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY; - if (length == 0) return STATUS_OK; - - char16_t* array = getter(*arrayData); + if (length <= 0) return STATUS_OK; if (array == nullptr) return STATUS_NO_MEMORY; int32_t size = 0; @@ -144,15 +163,16 @@ binder_status_t ReadArray<char16_t>(const AParcel* parcel, void** arrayData, } template <typename T> -binder_status_t WriteArray(AParcel* parcel, const void* arrayData, ArrayGetter<T> getter, - size_t length, status_t (Parcel::*write)(T)) { - if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE; +binder_status_t WriteArray(AParcel* parcel, const void* arrayData, int32_t length, + ArrayGetter<T> getter, status_t (Parcel::*write)(T)) { + // we have no clue if arrayData represents a null object or not, we can only infer from length + bool arrayIsNull = length < 0; + binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length); + if (status != STATUS_OK) return status; + if (length <= 0) return STATUS_OK; Parcel* rawParcel = parcel->get(); - status_t status = rawParcel->writeInt32(static_cast<int32_t>(length)); - if (status != STATUS_OK) return PruneStatusT(status); - for (size_t i = 0; i < length; i++) { status = (rawParcel->*write)(getter(arrayData, i)); @@ -163,26 +183,26 @@ binder_status_t WriteArray(AParcel* parcel, const void* arrayData, ArrayGetter<T } template <typename T> -binder_status_t ReadArray(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, ArraySetter<T> setter, - status_t (Parcel::*read)(T*) const) { +binder_status_t ReadArray(const AParcel* parcel, void* arrayData, ArrayAllocator<T> allocator, + ArraySetter<T> setter, status_t (Parcel::*read)(T*) const) { const Parcel* rawParcel = parcel->get(); int32_t length; status_t status = rawParcel->readInt32(&length); if (status != STATUS_OK) return PruneStatusT(status); - if (length < 0) return STATUS_UNEXPECTED_NULL; + if (length < -1) return STATUS_BAD_VALUE; + + if (!allocator(arrayData, length)) return STATUS_NO_MEMORY; - *arrayData = reallocator(*arrayData, length); - if (*arrayData == nullptr) return STATUS_NO_MEMORY; + if (length <= 0) return STATUS_OK; for (size_t i = 0; i < length; i++) { T readTarget; status = (rawParcel->*read)(&readTarget); if (status != STATUS_OK) return PruneStatusT(status); - setter(*arrayData, i, readTarget); + setter(arrayData, i, readTarget); } return STATUS_OK; @@ -192,13 +212,26 @@ void AParcel_delete(AParcel* parcel) { delete parcel; } +binder_status_t AParcel_setDataPosition(const AParcel* parcel, int32_t position) { + if (position < 0) { + return STATUS_BAD_VALUE; + } + + parcel->get()->setDataPosition(position); + return STATUS_OK; +} + +int32_t AParcel_getDataPosition(const AParcel* parcel) { + return parcel->get()->dataPosition(); +} + binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) { sp<IBinder> writeBinder = binder != nullptr ? binder->getBinder() : nullptr; return parcel->get()->writeStrongBinder(writeBinder); } binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder) { sp<IBinder> readBinder = nullptr; - status_t status = parcel->get()->readStrongBinder(&readBinder); + status_t status = parcel->get()->readNullableStrongBinder(&readBinder); if (status != STATUS_OK) { return PruneStatusT(status); } @@ -207,32 +240,73 @@ binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binde *binder = ret.get(); return PruneStatusT(status); } -binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder) { - sp<IBinder> readBinder = nullptr; - status_t status = parcel->get()->readNullableStrongBinder(&readBinder); - if (status != STATUS_OK) { - return PruneStatusT(status); + +binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) { + std::unique_ptr<ParcelFileDescriptor> parcelFd; + + if (fd < 0) { + if (fd != -1) { + return STATUS_UNKNOWN_ERROR; + } + // parcelFd = nullptr + } else { // fd >= 0 + parcelFd = std::make_unique<ParcelFileDescriptor>(unique_fd(fd)); } - sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(readBinder); - AIBinder_incStrong(ret.get()); - *binder = ret.get(); + + status_t status = parcel->get()->writeNullableParcelable(parcelFd); + + // ownership is retained by caller + if (parcelFd != nullptr) { + (void)parcelFd->release().release(); + } + return PruneStatusT(status); } + +binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) { + std::unique_ptr<ParcelFileDescriptor> parcelFd; + + status_t status = parcel->get()->readParcelable(&parcelFd); + if (status != STATUS_OK) return PruneStatusT(status); + + if (parcelFd) { + *fd = parcelFd->release().release(); + } else { + *fd = -1; + } + + return STATUS_OK; +} + binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status) { return PruneStatusT(status->get()->writeToParcel(parcel->get())); } binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status) { ::android::binder::Status bstatus; binder_status_t ret = PruneStatusT(bstatus.readFromParcel(*parcel->get())); - if (ret == EX_NONE) { + if (ret == STATUS_OK) { *status = new AStatus(std::move(bstatus)); } - return ret; + return PruneStatusT(ret); } -binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) { - const uint8_t* str8 = (uint8_t*)string; +binder_status_t AParcel_writeString(AParcel* parcel, const char* string, int32_t length) { + if (string == nullptr) { + if (length != -1) { + LOG(WARNING) << __func__ << ": null string must be used with length == -1."; + return STATUS_BAD_VALUE; + } + status_t err = parcel->get()->writeInt32(-1); + return PruneStatusT(err); + } + + if (length < 0) { + LOG(WARNING) << __func__ << ": Negative string length: " << length; + return STATUS_BAD_VALUE; + } + + const uint8_t* str8 = (uint8_t*)string; const ssize_t len16 = utf8_to_utf16_length(str8, length); if (len16 < 0 || len16 >= std::numeric_limits<int32_t>::max()) { @@ -255,13 +329,16 @@ binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t return STATUS_OK; } -binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringReallocator reallocator, - AParcel_stringGetter getter, void** stringData) { +binder_status_t AParcel_readString(const AParcel* parcel, void* stringData, + AParcel_stringAllocator allocator) { size_t len16; const char16_t* str16 = parcel->get()->readString16Inplace(&len16); if (str16 == nullptr) { - LOG(WARNING) << __func__ << ": Failed to read string in place."; + if (allocator(stringData, -1, nullptr)) { + return STATUS_OK; + } + return STATUS_UNEXPECTED_NULL; } @@ -273,25 +350,85 @@ binder_status_t AParcel_readString(const AParcel* parcel, AParcel_stringRealloca len8 = utf16_to_utf8_length(str16, len16) + 1; } - if (len8 <= 0 || len8 >= std::numeric_limits<int32_t>::max()) { + if (len8 <= 0 || len8 > std::numeric_limits<int32_t>::max()) { LOG(WARNING) << __func__ << ": Invalid string length: " << len8; return STATUS_BAD_VALUE; } - *stringData = reallocator(*stringData, len8); + char* str8; + bool success = allocator(stringData, len8, &str8); - if (*stringData == nullptr) { + if (!success || str8 == nullptr) { + LOG(WARNING) << __func__ << ": AParcel_stringAllocator failed to allocate."; return STATUS_NO_MEMORY; } - char* str8 = getter(*stringData); + utf16_to_utf8(str16, len16, str8, len8); - if (str8 == nullptr) { - LOG(WARNING) << __func__ << ": AParcel_stringReallocator failed to allocate."; - return STATUS_NO_MEMORY; + return STATUS_OK; +} + +binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length, + AParcel_stringArrayElementGetter getter) { + // we have no clue if arrayData represents a null object or not, we can only infer from length + bool arrayIsNull = length < 0; + binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length); + if (status != STATUS_OK) return status; + if (length <= 0) return STATUS_OK; + + for (size_t i = 0; i < length; i++) { + size_t length = 0; + const char* str = getter(arrayData, i, &length); + if (str == nullptr && length != -1) return STATUS_BAD_VALUE; + + binder_status_t status = AParcel_writeString(parcel, str, length); + if (status != STATUS_OK) return status; } - utf16_to_utf8(str16, len16, str8, len8); + return STATUS_OK; +} + +// This implements AParcel_stringAllocator for a string using an array, index, and element +// allocator. +struct StringArrayElementAllocationAdapter { + void* arrayData; // stringData from the NDK + size_t index; // index into the string array + AParcel_stringArrayElementAllocator elementAllocator; + + static bool Allocator(void* stringData, int32_t length, char** buffer) { + StringArrayElementAllocationAdapter* adapter = + static_cast<StringArrayElementAllocationAdapter*>(stringData); + return adapter->elementAllocator(adapter->arrayData, adapter->index, length, buffer); + } +}; + +binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData, + AParcel_stringArrayAllocator allocator, + AParcel_stringArrayElementAllocator elementAllocator) { + const Parcel* rawParcel = parcel->get(); + + int32_t length; + status_t status = rawParcel->readInt32(&length); + + if (status != STATUS_OK) return PruneStatusT(status); + if (length < -1) return STATUS_BAD_VALUE; + + if (!allocator(arrayData, length)) return STATUS_NO_MEMORY; + + if (length == -1) return STATUS_OK; // null string array + + StringArrayElementAllocationAdapter adapter{ + .arrayData = arrayData, + .index = 0, + .elementAllocator = elementAllocator, + }; + + for (; adapter.index < length; adapter.index++) { + binder_status_t status = AParcel_readString(parcel, static_cast<void*>(&adapter), + StringArrayElementAllocationAdapter::Allocator); + + if (status != STATUS_OK) return status; + } return STATUS_OK; } @@ -389,95 +526,89 @@ binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) { return PruneStatusT(status); } -binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* value, size_t length) { - return WriteArray<int32_t>(parcel, value, length); +binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, int32_t length) { + return WriteArray<int32_t>(parcel, arrayData, length); } -binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* value, size_t length) { - return WriteArray<uint32_t>(parcel, value, length); +binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData, + int32_t length) { + return WriteArray<uint32_t>(parcel, arrayData, length); } -binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* value, size_t length) { - return WriteArray<int64_t>(parcel, value, length); +binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, int32_t length) { + return WriteArray<int64_t>(parcel, arrayData, length); } -binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* value, size_t length) { - return WriteArray<uint64_t>(parcel, value, length); +binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData, + int32_t length) { + return WriteArray<uint64_t>(parcel, arrayData, length); } -binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* value, size_t length) { - return WriteArray<float>(parcel, value, length); +binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, int32_t length) { + return WriteArray<float>(parcel, arrayData, length); } -binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* value, size_t length) { - return WriteArray<double>(parcel, value, length); +binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, int32_t length) { + return WriteArray<double>(parcel, arrayData, length); } -binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, - AParcel_boolArrayGetter getter, size_t length) { - return WriteArray<bool>(parcel, arrayData, getter, length, &Parcel::writeBool); +binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, int32_t length, + AParcel_boolArrayGetter getter) { + return WriteArray<bool>(parcel, arrayData, length, getter, &Parcel::writeBool); } -binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* value, size_t length) { - return WriteArray<char16_t>(parcel, value, length); +binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, int32_t length) { + return WriteArray<char16_t>(parcel, arrayData, length); } -binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* value, size_t length) { - return WriteArray<int8_t>(parcel, value, length); +binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, int32_t length) { + return WriteArray<int8_t>(parcel, arrayData, length); } -binder_status_t AParcel_readInt32Array(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_int32ArrayGetter getter) { - return ReadArray<int32_t>(parcel, arrayData, reallocator, getter); +binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData, + AParcel_int32ArrayAllocator allocator) { + return ReadArray<int32_t>(parcel, arrayData, allocator); } -binder_status_t AParcel_readUint32Array(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_uint32ArrayGetter getter) { - return ReadArray<uint32_t>(parcel, arrayData, reallocator, getter); +binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData, + AParcel_uint32ArrayAllocator allocator) { + return ReadArray<uint32_t>(parcel, arrayData, allocator); } -binder_status_t AParcel_readInt64Array(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_int64ArrayGetter getter) { - return ReadArray<int64_t>(parcel, arrayData, reallocator, getter); +binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData, + AParcel_int64ArrayAllocator allocator) { + return ReadArray<int64_t>(parcel, arrayData, allocator); } -binder_status_t AParcel_readUint64Array(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_uint64ArrayGetter getter) { - return ReadArray<uint64_t>(parcel, arrayData, reallocator, getter); +binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData, + AParcel_uint64ArrayAllocator allocator) { + return ReadArray<uint64_t>(parcel, arrayData, allocator); } -binder_status_t AParcel_readFloatArray(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_floatArrayGetter getter) { - return ReadArray<float>(parcel, arrayData, reallocator, getter); +binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData, + AParcel_floatArrayAllocator allocator) { + return ReadArray<float>(parcel, arrayData, allocator); } -binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_doubleArrayGetter getter) { - return ReadArray<double>(parcel, arrayData, reallocator, getter); +binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData, + AParcel_doubleArrayAllocator allocator) { + return ReadArray<double>(parcel, arrayData, allocator); } -binder_status_t AParcel_readBoolArray(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, +binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData, + AParcel_boolArrayAllocator allocator, AParcel_boolArraySetter setter) { - return ReadArray<bool>(parcel, arrayData, reallocator, setter, &Parcel::readBool); + return ReadArray<bool>(parcel, arrayData, allocator, setter, &Parcel::readBool); } -binder_status_t AParcel_readCharArray(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_charArrayGetter getter) { - return ReadArray<char16_t>(parcel, arrayData, reallocator, getter); +binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData, + AParcel_charArrayAllocator allocator) { + return ReadArray<char16_t>(parcel, arrayData, allocator); } -binder_status_t AParcel_readByteArray(const AParcel* parcel, void** arrayData, - AParcel_arrayReallocator reallocator, - AParcel_byteArrayGetter getter) { - return ReadArray<int8_t>(parcel, arrayData, reallocator, getter); +binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData, + AParcel_byteArrayAllocator allocator) { + return ReadArray<int8_t>(parcel, arrayData, allocator); } // @END diff --git a/libs/binder/ndk/parcel_internal.h b/libs/binder/ndk/parcel_internal.h index d69971fdb6..f29230905a 100644 --- a/libs/binder/ndk/parcel_internal.h +++ b/libs/binder/ndk/parcel_internal.h @@ -29,7 +29,7 @@ struct AParcel { AParcel(const AIBinder* binder) : AParcel(binder, new ::android::Parcel, true /*owns*/) {} AParcel(const AIBinder* binder, ::android::Parcel* parcel, bool owns) - : mBinder(binder), mParcel(parcel), mOwns(owns) {} + : mBinder(binder), mParcel(parcel), mOwns(owns) {} ~AParcel() { if (mOwns) { @@ -43,7 +43,7 @@ struct AParcel { const AIBinder* getBinder() { return mBinder; } -private: + private: // This object is associated with a calls to a specific AIBinder object. This is used for sanity // checking to make sure that a parcel is one that is expected. const AIBinder* mBinder; diff --git a/libs/binder/ndk/runtests.sh b/libs/binder/ndk/runtests.sh index 2257eb27c1..a0c49fb167 100755 --- a/libs/binder/ndk/runtests.sh +++ b/libs/binder/ndk/runtests.sh @@ -22,12 +22,13 @@ fi set -ex function run_libbinder_ndk_test() { - adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server & - local pid=$! - trap "kill $pid" ERR - adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client - trap '' ERR - kill $pid + adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server & + + # avoid getService 1s delay for most runs, non-critical + sleep 0.1 + + adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client; \ + adb shell killall libbinder_ndk_test_server } [ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \ @@ -40,4 +41,5 @@ adb sync data # very simple unit tests, tests things outside of the NDK as well run_libbinder_ndk_test -atest android.binder.cts.NdkBinderTest +# CTS tests (much more comprehensive, new tests should ideally go here) +atest android.binder.cts diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py index 45f8d06883..8f587d2ccf 100755 --- a/libs/binder/ndk/scripts/gen_parcel_helper.py +++ b/libs/binder/ndk/scripts/gen_parcel_helper.py @@ -69,6 +69,11 @@ def main(): for pretty, cpp in data_types: header += "/**\n" header += " * Writes " + cpp + " value to the next location in a non-null parcel.\n" + header += " *\n" + header += " * \\param parcel the parcel to write to.\n" + header += " * \\param value the value to write to the parcel.\n" + header += " *\n" + header += " * \\return STATUS_OK on successful write.\n" header += " */\n" header += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) __INTRODUCED_IN(29);\n\n" source += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) {\n" @@ -79,6 +84,11 @@ def main(): for pretty, cpp in data_types: header += "/**\n" header += " * Reads into " + cpp + " value from the next location in a non-null parcel.\n" + header += " *\n" + header += " * \\param parcel the parcel to read from.\n" + header += " * \\param value the value to read from the parcel.\n" + header += " *\n" + header += " * \\return STATUS_OK on successful read.\n" header += " */\n" header += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) __INTRODUCED_IN(29);\n\n" source += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) {\n" @@ -89,87 +99,179 @@ def main(): for pretty, cpp in data_types: nca = pretty in non_contiguously_addressable - arg_type = "const " + cpp + "* value" - if nca: arg_type = "const void* arrayData, AParcel_" + pretty.lower() + "ArrayGetter getter" - args = "value, length" - if nca: args = "arrayData, getter, length, &Parcel::write" + pretty + arg_types = "const " + cpp + "* arrayData, int32_t length" + if nca: arg_types = "const void* arrayData, int32_t length, AParcel_" + pretty.lower() + "ArrayGetter getter" + args = "arrayData, length" + if nca: args = "arrayData, length, getter, &Parcel::write" + pretty header += "/**\n" header += " * Writes an array of " + cpp + " to the next location in a non-null parcel.\n" + if nca: + header += " *\n" + header += " * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying values to write " + header += "to the parcel.\n" + header += " *\n" + header += " * \\param parcel the parcel to write to.\n" + if nca: + header += " * \\param arrayData some external representation of an array.\n" + header += " * \\param length the length of arrayData (or -1 if this represents a null array).\n" + header += " * \\param getter the callback to retrieve data at specific locations in the array.\n" + else: + header += " * \\param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).\n" + header += " * \\param length the length of arrayData or -1 if this represents a null array.\n" + header += " *\n" + header += " * \\return STATUS_OK on successful write.\n" header += " */\n" - header += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_type + ", size_t length) __INTRODUCED_IN(29);\n\n" - source += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_type + ", size_t length) {\n" + header += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_types + ") __INTRODUCED_IN(29);\n\n" + source += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_types + ") {\n" source += " return WriteArray<" + cpp + ">(parcel, " + args + ");\n"; source += "}\n\n" for pretty, cpp in data_types: nca = pretty in non_contiguously_addressable - extra_getter_args = "" - if nca: extra_getter_args = ", size_t index" - getter_return = cpp + "*" - if nca: getter_return = cpp - getter_array_data = "void* arrayData" - if nca: getter_array_data = "const void* arrayData" - + read_func = "AParcel_read" + pretty + "Array" + write_func = "AParcel_write" + pretty + "Array" + allocator_type = "AParcel_" + pretty.lower() + "ArrayAllocator" getter_type = "AParcel_" + pretty.lower() + "ArrayGetter" setter_type = "AParcel_" + pretty.lower() + "ArraySetter" - pre_header += "/**\n" - pre_header += " * This is called to get the underlying data from an arrayData object.\n" - pre_header += " *\n" - pre_header += " * This will never be called for an empty array.\n" - pre_header += " */\n" - pre_header += "typedef " + getter_return + " (*" + getter_type + ")(" + getter_array_data + extra_getter_args + ");\n\n" - if nca: pre_header += "/**\n" + pre_header += " * This allocates an array of size 'length' inside of arrayData and returns whether or not there was " + pre_header += "a success. If length is -1, then this should allocate some representation of a null array.\n" + pre_header += " *\n" + pre_header += " * See also " + read_func + "\n" + pre_header += " *\n" + pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n" + pre_header += " * \\param length the length to allocate arrayData to (or -1 if this represents a null array).\n" + pre_header += " *\n" + pre_header += " * \\return whether the allocation succeeded.\n" + pre_header += " */\n" + pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, int32_t length);\n\n" + + pre_header += "/**\n" + pre_header += " * This is called to get the underlying data from an arrayData object at index.\n" + pre_header += " *\n" + pre_header += " * See also " + write_func + "\n" + pre_header += " *\n" + pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n" + pre_header += " * \\param index the index of the value to be retrieved.\n" + pre_header += " *\n" + pre_header += " * \\return the value of the array at index index.\n" + pre_header += " */\n" + pre_header += "typedef " + cpp + " (*" + getter_type + ")(const void* arrayData, size_t index);\n\n" + + pre_header += "/**\n" pre_header += " * This is called to set an underlying value in an arrayData object at index.\n" + pre_header += " *\n" + pre_header += " * See also " + read_func + "\n" + pre_header += " *\n" + pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n" + pre_header += " * \\param index the index of the value to be set.\n" + pre_header += " * \\param value the value to set at index index.\n" pre_header += " */\n" pre_header += "typedef void (*" + setter_type + ")(void* arrayData, size_t index, " + cpp + " value);\n\n" + else: + pre_header += "/**\n" + pre_header += " * This is called to get the underlying data from an arrayData object.\n" + pre_header += " *\n" + pre_header += " * The implementation of this function should allocate a contiguous array of size 'length' and " + pre_header += "return that underlying buffer to be filled out. If there is an error or length is 0, null may be " + pre_header += "returned. If length is -1, this should allocate some representation of a null array.\n" + pre_header += " *\n" + pre_header += " * See also " + read_func + "\n" + pre_header += " *\n" + pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n" + pre_header += " * \\param length the length to allocate arrayData to.\n" + pre_header += " * \\param outBuffer a buffer of " + cpp + " of size 'length' (if length is >= 0, if length is 0, " + pre_header += "this may be nullptr).\n" + pre_header += " *\n" + pre_header += " * \\return whether or not the allocation was successful (or whether a null array is represented when length is -1).\n" + pre_header += " */\n" + pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, int32_t length, " + cpp + "** outBuffer);\n\n" - read_using = "getter" - if nca: read_using = "setter" - read_type = getter_type - if nca: read_type = setter_type + read_array_args = [("const AParcel*", "parcel")] + read_array_args += [("void*", "arrayData")] + read_array_args += [(allocator_type, "allocator")] + if nca: read_array_args += [(setter_type, "setter")] - arguments = ["const AParcel* parcel"] - arguments += ["void** arrayData"] - arguments += ["AParcel_arrayReallocator reallocator"] - arguments += [read_type + " " + read_using] - arguments = ", ".join(arguments) + read_type_args = ", ".join((varType + " " + name for varType, name in read_array_args)) + read_call_args = ", ".join((name for varType, name in read_array_args)) header += "/**\n" header += " * Reads an array of " + cpp + " from the next location in a non-null parcel.\n" + header += " *\n" + if nca: + header += " * First, allocator will be called with the length of the array. Then, for every i in [0, length), " + header += "setter(arrayData, i, x) will be called where x is the value at the associated index.\n" + else: + header += " * First, allocator will be called with the length of the array. If the allocation succeeds and the " + header += "length is greater than zero, the buffer returned by the allocator will be filled with the corresponding data\n" + header += " *\n" + header += " * \\param parcel the parcel to read from.\n" + header += " * \\param arrayData some external representation of an array.\n" + header += " * \\param allocator the callback that will be called to allocate the array.\n" + if nca: + header += " * \\param setter the callback that will be called to set a value at a specific location in the array.\n" + header += " *\n" + header += " * \\return STATUS_OK on successful read.\n" header += " */\n" - header += "binder_status_t AParcel_read" + pretty + "Array(" + arguments + ") __INTRODUCED_IN(29);\n\n" - source += "binder_status_t AParcel_read" + pretty + "Array(" + arguments + ") {\n" + header += "binder_status_t " + read_func + "(" + read_type_args + ") __INTRODUCED_IN(29);\n\n" + source += "binder_status_t " + read_func + "(" + read_type_args + ") {\n" additional_args = "" if nca: additional_args = ", &Parcel::read" + pretty - source += " return ReadArray<" + cpp + ">(parcel, arrayData, reallocator, " + read_using + additional_args + ");\n"; + source += " return ReadArray<" + cpp + ">(" + read_call_args + additional_args + ");\n"; source += "}\n\n" cpp_helper += "/**\n" cpp_helper += " * Writes a vector of " + cpp + " to the next location in a non-null parcel.\n" cpp_helper += " */\n" - cpp_helper += "template<>\n" - cpp_helper += "inline binder_status_t AParcel_writeVector<" + cpp + ">(AParcel* parcel, const std::vector<" + cpp + ">& vec) {\n" - write_args = "vec.data()" - if nca: write_args = "static_cast<const void*>(&vec), AParcel_stdVectorGetter<" + cpp + ">" - cpp_helper += " return AParcel_write" + pretty + "Array(parcel, " + write_args + ", vec.size());\n" + cpp_helper += "inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<" + cpp + ">& vec) {\n" + write_args = "vec.data(), vec.size()" + if nca: write_args = "static_cast<const void*>(&vec), vec.size(), AParcel_stdVectorGetter<" + cpp + ">" + cpp_helper += " return AParcel_write" + pretty + "Array(parcel, " + write_args + ");\n" + cpp_helper += "}\n\n" + + cpp_helper += "/**\n" + cpp_helper += " * Writes an optional vector of " + cpp + " to the next location in a non-null parcel.\n" + cpp_helper += " */\n" + cpp_helper += "inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::optional<std::vector<" + cpp + ">>& vec) {\n" + extra_args = "" + if nca: extra_args = ", AParcel_stdVectorGetter<" + cpp + ">" + cpp_helper += " if (!vec) return AParcel_write" + pretty + "Array(parcel, nullptr, -1" + extra_args + ");\n" + cpp_helper += " return AParcel_writeVector(parcel, *vec);\n" cpp_helper += "}\n\n" cpp_helper += "/**\n" cpp_helper += " * Reads a vector of " + cpp + " from the next location in a non-null parcel.\n" cpp_helper += " */\n" - cpp_helper += "template<>\n" - cpp_helper += "inline binder_status_t AParcel_readVector<" + cpp + ">(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n" + cpp_helper += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n" + cpp_helper += " void* vectorData = static_cast<void*>(vec);\n" + read_args = [] + read_args += ["parcel"] + read_args += ["vectorData"] + if nca: + read_args += ["AParcel_stdVectorExternalAllocator<bool>"] + read_args += ["AParcel_stdVectorSetter<" + cpp + ">"] + else: + read_args += ["AParcel_stdVectorAllocator<" + cpp + ">"] + cpp_helper += " return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n" + cpp_helper += "}\n\n" + + cpp_helper += "/**\n" + cpp_helper += " * Reads an optional vector of " + cpp + " from the next location in a non-null parcel.\n" + cpp_helper += " */\n" + cpp_helper += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::optional<std::vector<" + cpp + ">>* vec) {\n" cpp_helper += " void* vectorData = static_cast<void*>(vec);\n" read_args = [] read_args += ["parcel"] - read_args += ["&vectorData"] - read_args += ["&AParcel_stdVectorReallocator<" + cpp + ">"] - read_args += ["AParcel_stdVector" + read_using.capitalize() + "<" + cpp + ">"] + read_args += ["vectorData"] + if nca: + read_args += ["AParcel_nullableStdVectorExternalAllocator<bool>"] + read_args += ["AParcel_nullableStdVectorSetter<" + cpp + ">"] + else: + read_args += ["AParcel_nullableStdVectorAllocator<" + cpp + ">"] cpp_helper += " return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n" cpp_helper += "}\n\n" diff --git a/libs/binder/ndk/status_internal.h b/libs/binder/ndk/status_internal.h index 8c32baf83f..d39f0d887c 100644 --- a/libs/binder/ndk/status_internal.h +++ b/libs/binder/ndk/status_internal.h @@ -22,13 +22,13 @@ #include <utils/Errors.h> struct AStatus { - AStatus() {} // ok + AStatus() {} // ok AStatus(::android::binder::Status&& status) : mStatus(std::move(status)) {} ::android::binder::Status* get() { return &mStatus; } const ::android::binder::Status* get() const { return &mStatus; } -private: + private: ::android::binder::Status mStatus; }; diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp index 8e40a01369..67481cf59b 100644 --- a/libs/binder/ndk/test/Android.bp +++ b/libs/binder/ndk/test/Android.bp @@ -14,9 +14,6 @@ * limitations under the License. */ -// This test is a unit test of the low-level API that is presented here. -// Actual users should use AIDL to generate these complicated stubs. - cc_defaults { name: "test_libbinder_ndk_defaults", shared_libs: [ @@ -25,6 +22,7 @@ cc_defaults { strip: { none: true, }, + cpp_std: "c++17", cflags: [ "-O0", "-g", @@ -55,6 +53,9 @@ cc_defaults { ], } +// This test is a unit test of the low-level API that is presented here, +// specifically the parts which are outside of the NDK. Actual users should +// also instead use AIDL to generate these stubs. See android.binder.cts. cc_test { name: "libbinder_ndk_test_client", defaults: ["test_libbinder_ndk_test_defaults"], diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/test/iface.cpp index 0dc3cc4f95..6ef964e896 100644 --- a/libs/binder/ndk/test/iface.cpp +++ b/libs/binder/ndk/test/iface.cpp @@ -18,10 +18,13 @@ #include <android/binder_manager.h> #include <iface/iface.h> +#include <android/binder_auto_utils.h> + using ::android::sp; using ::android::wp; const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo"; +const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die"; const char* kIFooDescriptor = "my-special-IFoo-class"; struct IFoo_Class_Data { @@ -49,12 +52,18 @@ binder_status_t IFoo_Class_onTransact(AIBinder* binder, transaction_code_t code, switch (code) { case IFoo::DOFOO: { int32_t valueIn; + int32_t valueOut; stat = AParcel_readInt32(in, &valueIn); if (stat != STATUS_OK) break; - int32_t valueOut = foo->doubleNumber(valueIn); + stat = foo->doubleNumber(valueIn, &valueOut); + if (stat != STATUS_OK) break; stat = AParcel_writeInt32(out, valueOut); break; } + case IFoo::DIE: { + stat = foo->die(); + break; + } } return stat; @@ -64,29 +73,43 @@ AIBinder_Class* IFoo::kClass = AIBinder_Class_define(kIFooDescriptor, IFoo_Class IFoo_Class_onDestroy, IFoo_Class_onTransact); class BpFoo : public IFoo { -public: + public: BpFoo(AIBinder* binder) : mBinder(binder) {} virtual ~BpFoo() { AIBinder_decStrong(mBinder); } - virtual int32_t doubleNumber(int32_t in) { + virtual binder_status_t doubleNumber(int32_t in, int32_t* out) { + binder_status_t stat = STATUS_OK; + AParcel* parcelIn; - CHECK(STATUS_OK == AIBinder_prepareTransaction(mBinder, &parcelIn)); + stat = AIBinder_prepareTransaction(mBinder, &parcelIn); + if (stat != STATUS_OK) return stat; + + stat = AParcel_writeInt32(parcelIn, in); + if (stat != STATUS_OK) return stat; - CHECK(STATUS_OK == AParcel_writeInt32(parcelIn, in)); + ::ndk::ScopedAParcel parcelOut; + stat = AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, parcelOut.getR(), 0 /*flags*/); + if (stat != STATUS_OK) return stat; - AParcel* parcelOut; - CHECK(STATUS_OK == - AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, &parcelOut, 0 /*flags*/)); + stat = AParcel_readInt32(parcelOut.get(), out); + if (stat != STATUS_OK) return stat; - int32_t out; - CHECK(STATUS_OK == AParcel_readInt32(parcelOut, &out)); + return stat; + } + + virtual binder_status_t die() { + binder_status_t stat = STATUS_OK; + + AParcel* parcelIn; + stat = AIBinder_prepareTransaction(mBinder, &parcelIn); - AParcel_delete(parcelOut); + ::ndk::ScopedAParcel parcelOut; + stat = AIBinder_transact(mBinder, IFoo::DIE, &parcelIn, parcelOut.getR(), 0 /*flags*/); - return out; + return stat; } -private: + private: // Always assumes one refcount AIBinder* mBinder; }; @@ -117,8 +140,8 @@ binder_status_t IFoo::addService(const char* instance) { return status; } -sp<IFoo> IFoo::getService(const char* instance) { - AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr +sp<IFoo> IFoo::getService(const char* instance, AIBinder** outBinder) { + AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr if (binder == nullptr) { return nullptr; } @@ -128,14 +151,19 @@ sp<IFoo> IFoo::getService(const char* instance) { return nullptr; } + if (outBinder != nullptr) { + AIBinder_incStrong(binder); + *outBinder = binder; + } + if (AIBinder_isRemote(binder)) { - sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder + sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder return ret; } IFoo_Class_Data* data = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder)); - CHECK(data != nullptr); // always created with non-null data + CHECK(data != nullptr); // always created with non-null data sp<IFoo> ret = data->foo; @@ -143,7 +171,6 @@ sp<IFoo> IFoo::getService(const char* instance) { CHECK(held == binder); AIBinder_decStrong(held); - // IFoo only keeps a weak reference to AIBinder, so we can drop this AIBinder_decStrong(binder); return ret; } diff --git a/libs/binder/ndk/test/include/iface/iface.h b/libs/binder/ndk/test/include/iface/iface.h index 4c61e9d849..cdf5493216 100644 --- a/libs/binder/ndk/test/include/iface/iface.h +++ b/libs/binder/ndk/test/include/iface/iface.h @@ -19,22 +19,33 @@ #include <android/binder_ibinder.h> #include <utils/RefBase.h> +// warning: it is recommended to use AIDL output instead of this. binder_ibinder_utils.h and some of +// the other niceties make sure that, for instance, binder proxies are always the same. They also +// don't use internal Android APIs like refbase which are used here only for convenience. + class IFoo : public virtual ::android::RefBase { -public: + public: static const char* kSomeInstanceName; + static const char* kInstanceNameToDieFor; + static AIBinder_Class* kClass; // Takes ownership of IFoo binder_status_t addService(const char* instance); - static ::android::sp<IFoo> getService(const char* instance); + static ::android::sp<IFoo> getService(const char* instance, AIBinder** outBinder = nullptr); enum Call { DOFOO = FIRST_CALL_TRANSACTION + 0, + DIE = FIRST_CALL_TRANSACTION + 1, }; virtual ~IFoo(); - virtual int32_t doubleNumber(int32_t in) = 0; -private: - AIBinder_Weak* mWeakBinder = nullptr; // maybe owns AIBinder + virtual binder_status_t doubleNumber(int32_t in, int32_t* out) = 0; + virtual binder_status_t die() = 0; + + private: + // this variable is only when IFoo is local (since this test combines 'IFoo' and 'BnFoo'), not + // for BpFoo. + AIBinder_Weak* mWeakBinder = nullptr; }; diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp index 6945cac015..c159d71b59 100644 --- a/libs/binder/ndk/test/main_client.cpp +++ b/libs/binder/ndk/test/main_client.cpp @@ -21,6 +21,10 @@ #include <gtest/gtest.h> #include <iface/iface.h> +#include <chrono> +#include <condition_variable> +#include <mutex> + using ::android::sp; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; @@ -34,7 +38,47 @@ constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; TEST(NdkBinder, DoubleNumber) { sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName); ASSERT_NE(foo, nullptr); - EXPECT_EQ(2, foo->doubleNumber(1)); + + int32_t out; + EXPECT_EQ(STATUS_OK, foo->doubleNumber(1, &out)); + EXPECT_EQ(2, out); +} + +void LambdaOnDeath(void* cookie) { + auto onDeath = static_cast<std::function<void(void)>*>(cookie); + (*onDeath)(); +}; +TEST(NdkBinder, DeathRecipient) { + using namespace std::chrono_literals; + + AIBinder* binder; + sp<IFoo> foo = IFoo::getService(IFoo::kInstanceNameToDieFor, &binder); + ASSERT_NE(nullptr, foo.get()); + ASSERT_NE(nullptr, binder); + + std::mutex deathMutex; + std::condition_variable deathCv; + bool deathRecieved = false; + + std::function<void(void)> onDeath = [&] { + std::cerr << "Binder died (as requested)." << std::endl; + deathRecieved = true; + deathCv.notify_one(); + }; + + AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath); + + EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath))); + + // the binder driver should return this if the service dies during the transaction + EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die()); + + std::unique_lock<std::mutex> lock(deathMutex); + EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; })); + EXPECT_TRUE(deathRecieved); + + AIBinder_DeathRecipient_delete(recipient); + AIBinder_decStrong(binder); } TEST(NdkBinder, RetrieveNonNdkService) { @@ -52,9 +96,6 @@ void OnBinderDeath(void* cookie) { } TEST(NdkBinder, LinkToDeath) { - ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications - ABinderProcess_startThreadPool(); - AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); ASSERT_NE(nullptr, binder); @@ -72,9 +113,14 @@ TEST(NdkBinder, LinkToDeath) { } class MyTestFoo : public IFoo { - int32_t doubleNumber(int32_t in) override { - LOG(INFO) << "doubleNumber " << in; - return 2 * in; + binder_status_t doubleNumber(int32_t in, int32_t* out) override { + *out = 2 * in; + LOG(INFO) << "doubleNumber (" << in << ") => " << *out; + return STATUS_OK; + } + binder_status_t die() override { + ADD_FAILURE() << "die called on local instance"; + return STATUS_OK; } }; @@ -87,7 +133,9 @@ TEST(NdkBinder, GetServiceInProcess) { sp<IFoo> getFoo = IFoo::getService(kInstanceName); EXPECT_EQ(foo.get(), getFoo.get()); - EXPECT_EQ(2, getFoo->doubleNumber(1)); + int32_t out; + EXPECT_EQ(STATUS_OK, getFoo->doubleNumber(1, &out)); + EXPECT_EQ(2, out); } TEST(NdkBinder, EqualityOfRemoteBinderPointer) { @@ -132,6 +180,15 @@ TEST(NdkBinder, AddServiceMultipleTimes) { EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2)); } +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + + ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks + ABinderProcess_startThreadPool(); + + return RUN_ALL_TESTS(); +} + #include <android/binder_auto_utils.h> #include <android/binder_interface_utils.h> #include <android/binder_parcel_utils.h> diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp index 0718a69add..a6e17e8d98 100644 --- a/libs/binder/ndk/test/main_server.cpp +++ b/libs/binder/ndk/test/main_server.cpp @@ -21,23 +21,37 @@ using ::android::sp; class MyFoo : public IFoo { - int32_t doubleNumber(int32_t in) override { - LOG(INFO) << "doubling " << in; - return 2 * in; + binder_status_t doubleNumber(int32_t in, int32_t* out) override { + *out = 2 * in; + LOG(INFO) << "doubleNumber (" << in << ") => " << *out; + return STATUS_OK; + } + + binder_status_t die() override { + LOG(FATAL) << "IFoo::die called!"; + return STATUS_UNKNOWN_ERROR; } }; -int main() { +int service(const char* instance) { ABinderProcess_setThreadPoolMaxThreadCount(0); // Strong reference to MyFoo kept by service manager. - binder_status_t status = (new MyFoo)->addService(IFoo::kSomeInstanceName); + binder_status_t status = (new MyFoo)->addService(instance); if (status != STATUS_OK) { - LOG(FATAL) << "Could not register: " << status; + LOG(FATAL) << "Could not register: " << status << " " << instance; } ABinderProcess_joinThreadPool(); - return 1; + return 1; // should not return +} + +int main() { + if (fork() == 0) { + return service(IFoo::kInstanceNameToDieFor); + } + + return service(IFoo::kSomeInstanceName); } diff --git a/libs/binder/tests/binderValueTypeTest.cpp b/libs/binder/tests/binderValueTypeTest.cpp index c8f46977cd..15949d48c0 100644 --- a/libs/binder/tests/binderValueTypeTest.cpp +++ b/libs/binder/tests/binderValueTypeTest.cpp @@ -22,7 +22,6 @@ #include <vector> #include "android-base/file.h" -#include "android-base/test_utils.h" #include <gtest/gtest.h> #include <binder/Parcel.h> diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index f72e49b664..f834c559a4 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -327,8 +327,8 @@ void VelocityTracker::addMovement(const MotionEvent* event) { eventTime = event->getHistoricalEventTime(h); for (size_t i = 0; i < pointerCount; i++) { uint32_t index = pointerIndex[i]; - positions[index].x = event->getHistoricalRawX(i, h); - positions[index].y = event->getHistoricalRawY(i, h); + positions[index].x = event->getHistoricalX(i, h); + positions[index].y = event->getHistoricalY(i, h); } addMovement(eventTime, idBits, positions); } @@ -336,8 +336,8 @@ void VelocityTracker::addMovement(const MotionEvent* event) { eventTime = event->getEventTime(); for (size_t i = 0; i < pointerCount; i++) { uint32_t index = pointerIndex[i]; - positions[index].x = event->getRawX(i); - positions[index].y = event->getRawY(i); + positions[index].x = event->getX(i); + positions[index].y = event->getY(i); } addMovement(eventTime, idBits, positions); } diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 03824795ed..c1f1d2583f 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -65,12 +65,11 @@ GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, { } -GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, - PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage, std::string requestorName) - : GraphicBuffer() -{ - mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount, - usage, std::move(requestorName)); +GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, + uint32_t inLayerCount, uint64_t inUsage, std::string requestorName) + : GraphicBuffer() { + mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, + std::move(requestorName)); } // deprecated @@ -83,15 +82,12 @@ GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, { } -GraphicBuffer::GraphicBuffer(const native_handle_t* handle, - HandleWrapMethod method, uint32_t width, uint32_t height, - PixelFormat format, uint32_t layerCount, - uint64_t usage, - uint32_t stride) - : GraphicBuffer() -{ - mInitCheck = initWithHandle(handle, method, width, height, format, - layerCount, usage, stride); +GraphicBuffer::GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method, + uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, + uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride) + : GraphicBuffer() { + mInitCheck = initWithHandle(inHandle, method, inWidth, inHeight, inFormat, inLayerCount, + inUsage, inStride); } GraphicBuffer::~GraphicBuffer() @@ -183,26 +179,24 @@ status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight, return err; } -status_t GraphicBuffer::initWithHandle(const native_handle_t* handle, - HandleWrapMethod method, uint32_t width, uint32_t height, - PixelFormat format, uint32_t layerCount, uint64_t usage, - uint32_t stride) -{ - ANativeWindowBuffer::width = static_cast<int>(width); - ANativeWindowBuffer::height = static_cast<int>(height); - ANativeWindowBuffer::stride = static_cast<int>(stride); - ANativeWindowBuffer::format = format; - ANativeWindowBuffer::usage = usage; - ANativeWindowBuffer::usage_deprecated = int(usage); +status_t GraphicBuffer::initWithHandle(const native_handle_t* inHandle, HandleWrapMethod method, + uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, + uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride) { + ANativeWindowBuffer::width = static_cast<int>(inWidth); + ANativeWindowBuffer::height = static_cast<int>(inHeight); + ANativeWindowBuffer::stride = static_cast<int>(inStride); + ANativeWindowBuffer::format = inFormat; + ANativeWindowBuffer::usage = inUsage; + ANativeWindowBuffer::usage_deprecated = int(inUsage); - ANativeWindowBuffer::layerCount = layerCount; + ANativeWindowBuffer::layerCount = inLayerCount; mOwner = (method == WRAP_HANDLE) ? ownNone : ownHandle; if (method == TAKE_UNREGISTERED_HANDLE || method == CLONE_HANDLE) { buffer_handle_t importedHandle; - status_t err = mBufferMapper.importBuffer(handle, width, height, - layerCount, format, usage, stride, &importedHandle); + status_t err = mBufferMapper.importBuffer(inHandle, inWidth, inHeight, inLayerCount, + inFormat, inUsage, inStride, &importedHandle); if (err != NO_ERROR) { initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0); @@ -210,15 +204,15 @@ status_t GraphicBuffer::initWithHandle(const native_handle_t* handle, } if (method == TAKE_UNREGISTERED_HANDLE) { - native_handle_close(handle); - native_handle_delete(const_cast<native_handle_t*>(handle)); + native_handle_close(inHandle); + native_handle_delete(const_cast<native_handle_t*>(inHandle)); } - handle = importedHandle; - mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts); + inHandle = importedHandle; + mBufferMapper.getTransportSize(inHandle, &mTransportNumFds, &mTransportNumInts); } - ANativeWindowBuffer::handle = handle; + ANativeWindowBuffer::handle = inHandle; return NO_ERROR; } diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index cc38982e64..315db110a1 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -118,18 +118,16 @@ public: // cannot be used directly, such as one from hidl_handle. CLONE_HANDLE, }; - GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method, - uint32_t width, uint32_t height, - PixelFormat format, uint32_t layerCount, - uint64_t usage, uint32_t stride); + GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method, uint32_t inWidth, + uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage, + uint32_t inStride); // These functions are deprecated because they only take 32 bits of usage - GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method, - uint32_t width, uint32_t height, - PixelFormat format, uint32_t layerCount, - uint32_t usage, uint32_t stride) - : GraphicBuffer(handle, method, width, height, format, layerCount, - static_cast<uint64_t>(usage), stride) {} + GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method, uint32_t inWidth, + uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage, + uint32_t inStride) + : GraphicBuffer(inHandle, method, inWidth, inHeight, inFormat, inLayerCount, + static_cast<uint64_t>(inUsage), inStride) {} GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage, uint32_t inStride, native_handle_t* inHandle, bool keepOwnership); @@ -226,10 +224,9 @@ private: PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage, std::string requestorName); - status_t initWithHandle(const native_handle_t* handle, - HandleWrapMethod method, uint32_t width, uint32_t height, - PixelFormat format, uint32_t layerCount, - uint64_t usage, uint32_t stride); + status_t initWithHandle(const native_handle_t* inHandle, HandleWrapMethod method, + uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat, + uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride); void free_handle(); diff --git a/libs/vr/libpdx/status_tests.cpp b/libs/vr/libpdx/status_tests.cpp index d4e697caee..772c529947 100644 --- a/libs/vr/libpdx/status_tests.cpp +++ b/libs/vr/libpdx/status_tests.cpp @@ -2,6 +2,8 @@ #include <gtest/gtest.h> +#include <memory> + using android::pdx::ErrorStatus; using android::pdx::Status; @@ -84,8 +86,8 @@ TEST(Status, Move) { Status<std::unique_ptr<int>> status1; Status<std::unique_ptr<int>> status2; - status1 = Status<std::unique_ptr<int>>{std::unique_ptr<int>{new int{11}}}; - status2 = Status<std::unique_ptr<int>>{std::unique_ptr<int>{new int{12}}}; + status1 = Status<std::unique_ptr<int>>{std::make_unique<int>(int{11})}; + status2 = Status<std::unique_ptr<int>>{std::make_unique<int>(int{12})}; EXPECT_FALSE(status1.empty()); EXPECT_FALSE(status2.empty()); EXPECT_TRUE(status1.ok()); @@ -114,7 +116,7 @@ TEST(Status, Move) { } TEST(Status, Take) { - Status<std::unique_ptr<int>> status{std::unique_ptr<int>{new int{123}}}; + Status<std::unique_ptr<int>> status{std::make_unique<int>(int{123})}; EXPECT_FALSE(status.empty()); EXPECT_NE(nullptr, status.get()); diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 40adf8e229..36deedcb85 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -482,58 +482,35 @@ static EGLint getReportedColorSpace(EGLint colorspace) { } // Returns a list of color spaces understood by the vendor EGL driver. -static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp, - android_pixel_format format) { +static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp) { std::vector<EGLint> colorSpaces; - if (!dp->hasColorSpaceSupport) return colorSpaces; - - // OpenGL drivers only support sRGB encoding with 8-bit formats. - // RGB_888 is never returned by getNativePixelFormat, but is included for completeness. - const bool formatSupportsSRGBEncoding = - format == HAL_PIXEL_FORMAT_RGBA_8888 || format == HAL_PIXEL_FORMAT_RGBX_8888 || - format == HAL_PIXEL_FORMAT_RGB_888; - const bool formatIsFloatingPoint = format == HAL_PIXEL_FORMAT_RGBA_FP16; - - if (formatSupportsSRGBEncoding) { - // sRGB and linear are always supported when color space support is present. - colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR); - colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR); - // DCI-P3 uses the sRGB transfer function, so it's only relevant for 8-bit formats. - if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_display_p3")) { - colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT); - } - } - // According to the spec, scRGB is only supported for floating point formats. - // For non-linear scRGB, the application is responsible for applying the - // transfer function. - if (formatIsFloatingPoint) { - if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_scrgb")) { - colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT); - } - if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_scrgb_linear")) { - colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT); - } - } + // sRGB and linear are always supported when color space support is present. + colorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR); + colorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR); - // BT2020 can be used with any pixel format. PQ encoding must be applied by the - // application and does not affect the behavior of OpenGL. if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_bt2020_linear")) { + "EGL_EXT_gl_colorspace_display_p3")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT); + } + if (findExtension(dp->disp.queryString.extensions, + "EGL_EXT_gl_colorspace_scrgb")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_EXT); + } + if (findExtension(dp->disp.queryString.extensions, + "EGL_EXT_gl_colorspace_scrgb_linear")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT); + } + if (findExtension(dp->disp.queryString.extensions, + "EGL_EXT_gl_colorspace_bt2020_linear")) { colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT); } if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_bt2020_pq")) { + "EGL_EXT_gl_colorspace_bt2020_pq")) { colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_PQ_EXT); } - - // Linear DCI-P3 simply uses different primaries than standard RGB and thus - // can be used with any pixel format. if (findExtension(dp->disp.queryString.extensions, - "EGL_EXT_gl_colorspace_display_p3_linear")) { + "EGL_EXT_gl_colorspace_display_p3_linear")) { colorSpaces.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT); } return colorSpaces; @@ -543,19 +520,32 @@ static std::vector<EGLint> getDriverColorSpaces(egl_display_ptr dp, // If there is no color space attribute in attrib_list, colorSpace is left // unmodified. static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window, - android_pixel_format format, const EGLint* attrib_list, - EGLint* colorSpace, + const EGLint* attrib_list, EGLint* colorSpace, std::vector<EGLint>* strippedAttribList) { for (const EGLint* attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) { bool copyAttribute = true; if (attr[0] == EGL_GL_COLORSPACE_KHR) { - // Fail immediately if the driver doesn't have color space support at all. - if (!dp->hasColorSpaceSupport) return false; + switch (attr[1]) { + case EGL_GL_COLORSPACE_LINEAR_KHR: + case EGL_GL_COLORSPACE_SRGB_KHR: + case EGL_GL_COLORSPACE_DISPLAY_P3_EXT: + case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT: + case EGL_GL_COLORSPACE_SCRGB_EXT: + case EGL_GL_COLORSPACE_BT2020_LINEAR_EXT: + case EGL_GL_COLORSPACE_BT2020_PQ_EXT: + case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT: + // Fail immediately if the driver doesn't have color space support at all. + if (!dp->hasColorSpaceSupport) return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); + break; + default: + // BAD_ATTRIBUTE if attr is not any of the EGL_GL_COLORSPACE_* + return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } *colorSpace = attr[1]; // Strip the attribute if the driver doesn't understand it. copyAttribute = false; - std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp, format); + std::vector<EGLint> driverColorSpaces = getDriverColorSpaces(dp); for (auto driverColorSpace : driverColorSpaces) { if (attr[1] == driverColorSpace) { copyAttribute = true; @@ -603,12 +593,12 @@ static EGLBoolean processAttributes(egl_display_ptr dp, NativeWindowType window, ALOGE("processAttributes: invalid window (win=%p) " "failed (%#x) (already connected to another API?)", window, err); - return false; + return setError(EGL_BAD_NATIVE_WINDOW, EGL_FALSE); } if (!windowSupportsWideColor) { // Application has asked for a wide-color colorspace but // wide-color support isn't available on the display the window is on. - return false; + return setError(EGL_BAD_MATCH, EGL_FALSE); } } return true; @@ -736,10 +726,11 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, // now select correct colorspace and dataspace based on user's attribute list EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; - if (!processAttributes(dp, window, format, attrib_list, &colorSpace, + if (!processAttributes(dp, window, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); + return EGL_NO_SURFACE; } attrib_list = strippedAttribList.data(); @@ -754,14 +745,14 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, } android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace); - if (dataSpace != HAL_DATASPACE_UNKNOWN) { - int err = native_window_set_buffers_data_space(window, dataSpace); - if (err != 0) { - ALOGE("error setting native window pixel dataSpace: %s (%d)", - strerror(-err), err); - native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); - return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); - } + // Set dataSpace even if it could be HAL_DATASPACE_UNKNOWN. HAL_DATASPACE_UNKNOWN + // is the default value, but it may have changed at this point. + int err = native_window_set_buffers_data_space(window, dataSpace); + if (err != 0) { + ALOGE("error setting native window pixel dataSpace: %s (%d)", + strerror(-err), err); + native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); + return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); } // the EGL spec requires that a new EGLSurface default to swap interval @@ -801,10 +792,10 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, // now select a corresponding sRGB format if needed EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; - if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, + if (!processAttributes(dp, nullptr, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + return EGL_NO_SURFACE; } attrib_list = strippedAttribList.data(); @@ -835,10 +826,10 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, // Select correct colorspace based on user's attribute list EGLint colorSpace = EGL_UNKNOWN; std::vector<EGLint> strippedAttribList; - if (!processAttributes(dp, nullptr, format, attrib_list, &colorSpace, + if (!processAttributes(dp, nullptr, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); - return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + return EGL_NO_SURFACE; } attrib_list = strippedAttribList.data(); diff --git a/opengl/tests/EGLTest/Android.bp b/opengl/tests/EGLTest/Android.bp index f246077037..a9e873ac43 100644 --- a/opengl/tests/EGLTest/Android.bp +++ b/opengl/tests/EGLTest/Android.bp @@ -25,6 +25,7 @@ cc_test { "libhidltransport", "liblog", "libutils", + "libnativewindow", ], include_dirs: [ diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp index 5927dc14e8..459b1356b8 100644 --- a/opengl/tests/EGLTest/EGL_test.cpp +++ b/opengl/tests/EGLTest/EGL_test.cpp @@ -775,4 +775,169 @@ TEST_F(EGLTest, EGLConfig1010102) { EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); } + +TEST_F(EGLTest, EGLInvalidColorspaceAttribute) { + EGLConfig config; + + ASSERT_NO_FATAL_FAILURE(get8BitConfig(config)); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + + // Create a EGLSurface + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + consumer->consumerConnect(new DummyConsumer, false); + sp<Surface> mSTC = new Surface(producer); + sp<ANativeWindow> mANW = mSTC; + + EGLint winAttrs[] = { + // clang-format off + EGL_GL_COLORSPACE_KHR, EGL_BACK_BUFFER, + EGL_NONE, + // clang-format on + }; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + ASSERT_EQ(EGL_NO_SURFACE, eglSurface); +} + +TEST_F(EGLTest, EGLUnsupportedColorspaceFormatCombo) { + EGLint numConfigs; + EGLConfig config; + EGLBoolean success; + + const EGLint attrs[] = { + // clang-format off + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 16, + EGL_GREEN_SIZE, 16, + EGL_BLUE_SIZE, 16, + EGL_ALPHA_SIZE, 16, + EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT, + EGL_NONE, + // clang-format on + }; + success = eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs); + ASSERT_EQ(EGL_UNSIGNED_TRUE, success); + ASSERT_EQ(1, numConfigs); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + + // Create a EGLSurface + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + consumer->consumerConnect(new DummyConsumer, false); + sp<Surface> mSTC = new Surface(producer); + sp<ANativeWindow> mANW = mSTC; + + const EGLint winAttrs[] = { + // clang-format off + EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT, + EGL_NONE, + // clang-format on + }; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_BAD_MATCH, eglGetError()); + ASSERT_EQ(EGL_NO_SURFACE, eglSurface); +} + +TEST_F(EGLTest, EGLCreateWindowFailAndSucceed) { + EGLConfig config; + + ASSERT_NO_FATAL_FAILURE(get8BitConfig(config)); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + + // Create a EGLSurface + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + consumer->consumerConnect(new DummyConsumer, false); + sp<Surface> mSTC = new Surface(producer); + sp<ANativeWindow> mANW = mSTC; + + EGLint winAttrs[] = { + // clang-format off + EGL_GL_COLORSPACE_KHR, EGL_BACK_BUFFER, + EGL_NONE, + // clang-format on + }; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_BAD_ATTRIBUTE, eglGetError()); + ASSERT_EQ(EGL_NO_SURFACE, eglSurface); + + // Now recreate surface with a valid colorspace. Ensure proper cleanup is done + // in the first failed attempt (e.g. native_window_api_disconnect). + winAttrs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; + eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); +} + +TEST_F(EGLTest, EGLCreateWindowTwoColorspaces) { + EGLConfig config; + + ASSERT_NO_FATAL_FAILURE(get8BitConfig(config)); + + struct DummyConsumer : public BnConsumerListener { + void onFrameAvailable(const BufferItem& /* item */) override {} + void onBuffersReleased() override {} + void onSidebandStreamChanged() override {} + }; + + // Create a EGLSurface + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + consumer->consumerConnect(new DummyConsumer, false); + sp<Surface> mSTC = new Surface(producer); + sp<ANativeWindow> mANW = mSTC; + + const EGLint winAttrs[] = { + // clang-format off + EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_DISPLAY_P3_EXT, + EGL_NONE, + // clang-format on + }; + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), winAttrs); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + android_dataspace dataspace = static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(mANW.get())); + ASSERT_EQ(dataspace, HAL_DATASPACE_DISPLAY_P3); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); + + // Now create with default attribute (EGL_GL_COLORSPACE_LINEAR_KHR) + eglSurface = eglCreateWindowSurface(mEglDisplay, config, mANW.get(), NULL); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + ASSERT_NE(EGL_NO_SURFACE, eglSurface); + + dataspace = static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(mANW.get())); + // Make sure the dataspace has been reset to UNKNOWN + ASSERT_NE(dataspace, HAL_DATASPACE_DISPLAY_P3); + + EXPECT_TRUE(eglDestroySurface(mEglDisplay, eglSurface)); +} } diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp new file mode 100644 index 0000000000..250bbee350 --- /dev/null +++ b/services/gpuservice/Android.bp @@ -0,0 +1,74 @@ +filegroup { + name: "gpuservice_sources", + srcs: [ + "GpuService.cpp", + ], +} + +filegroup { + name: "gpuservice_binary_sources", + srcs: ["main_gpuservice.cpp"], +} + +cc_defaults { + name: "gpuservice_defaults", + cflags: [ + "-DLOG_TAG=\"GpuService\"", + "-Wall", + "-Werror", + "-Wformat", + "-Wthread-safety", + "-Wunused", + "-Wunreachable-code", + ], + cppflags: ["-std=c++1z"], + srcs: [ + ":gpuservice_sources", + ], + include_dirs: [ + "frameworks/native/vulkan/vkjson", + "frameworks/native/vulkan/include", + ], + shared_libs: [ + "libbinder", + "liblog", + "libutils", + "libvulkan", + ], + static_libs: [ + "libvkjson", + ], +} + +cc_defaults { + name: "gpuservice_production_defaults", + defaults: ["gpuservice_defaults"], + cflags: [ + "-fvisibility=hidden", + "-fwhole-program-vtables", // requires ThinLTO + ], + lto: { + thin: true, + }, +} + +cc_defaults { + name: "gpuservice_binary", + defaults: ["gpuservice_defaults"], + whole_static_libs: [ + "libsigchain", + ], + shared_libs: [ + "libbinder", + "liblog", + "libutils", + ], + ldflags: ["-Wl,--export-dynamic"], +} + +cc_binary { + name: "gpuservice", + defaults: ["gpuservice_binary"], + init_rc: ["gpuservice.rc"], + srcs: [":gpuservice_binary_sources"], +} diff --git a/services/surfaceflinger/GpuService.cpp b/services/gpuservice/GpuService.cpp index 71052fb563..150896cf91 100644 --- a/services/surfaceflinger/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -23,10 +23,7 @@ namespace android { -// ---------------------------------------------------------------------------- - -class BpGpuService : public BpInterface<IGpuService> -{ +class BpGpuService : public BpInterface<IGpuService> { public: explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {} }; @@ -34,19 +31,15 @@ public: IMPLEMENT_META_INTERFACE(GpuService, "android.ui.IGpuService"); status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags) -{ + Parcel* reply, uint32_t flags) { status_t status; switch (code) { case SHELL_COMMAND_TRANSACTION: { int in = data.readFileDescriptor(); int out = data.readFileDescriptor(); int err = data.readFileDescriptor(); - int argc = data.readInt32(); - Vector<String16> args; - for (int i = 0; i < argc && data.dataAvail() > 0; i++) { - args.add(data.readString16()); - } + std::vector<String16> args; + data.readString16Vector(&args); sp<IBinder> unusedCallback; sp<IResultReceiver> resultReceiver; if ((status = data.readNullableStrongBinder(&unusedCallback)) != OK) @@ -64,8 +57,6 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, } } -// ---------------------------------------------------------------------------- - namespace { status_t cmd_help(int out); status_t cmd_vkjson(int out, int err); @@ -73,11 +64,10 @@ namespace { const char* const GpuService::SERVICE_NAME = "gpu"; -GpuService::GpuService() {} +GpuService::GpuService() = default; status_t GpuService::shellCommand(int /*in*/, int out, int err, - Vector<String16>& args) -{ + std::vector<String16>& args) { ALOGV("GpuService::shellCommand"); for (size_t i = 0, n = args.size(); i < n; i++) ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).string()); @@ -93,8 +83,6 @@ status_t GpuService::shellCommand(int /*in*/, int out, int err, return BAD_VALUE; } -// ---------------------------------------------------------------------------- - namespace { status_t cmd_help(int out) { diff --git a/services/surfaceflinger/GpuService.h b/services/gpuservice/GpuService.h index b8c28d2495..e2b396ec7b 100644 --- a/services/surfaceflinger/GpuService.h +++ b/services/gpuservice/GpuService.h @@ -17,6 +17,8 @@ #ifndef ANDROID_GPUSERVICE_H #define ANDROID_GPUSERVICE_H +#include <vector> + #include <binder/IInterface.h> #include <cutils/compiler.h> @@ -34,22 +36,21 @@ public: class BnGpuService: public BnInterface<IGpuService> { protected: virtual status_t shellCommand(int in, int out, int err, - Vector<String16>& args) = 0; + std::vector<String16>& args) = 0; - virtual status_t onTransact(uint32_t code, const Parcel& data, + status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override; }; -class GpuService : public BnGpuService -{ +class GpuService : public BnGpuService { public: static const char* const SERVICE_NAME ANDROID_API; GpuService() ANDROID_API; protected: - virtual status_t shellCommand(int in, int out, int err, - Vector<String16>& args) override; + status_t shellCommand(int in, int out, int err, + std::vector<String16>& args) override; }; } // namespace android diff --git a/services/gpuservice/gpuservice.rc b/services/gpuservice/gpuservice.rc new file mode 100644 index 0000000000..65a5c2776a --- /dev/null +++ b/services/gpuservice/gpuservice.rc @@ -0,0 +1,4 @@ +service gpu /system/bin/gpuservice + class core + user gpu_service + group graphics diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp new file mode 100644 index 0000000000..64aafcab6a --- /dev/null +++ b/services/gpuservice/main_gpuservice.cpp @@ -0,0 +1,43 @@ +/* + * Copyright 2018 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. + */ + +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <sys/resource.h> +#include "GpuService.h" + +using namespace android; + +int main(int /* argc */, char** /* argv */) { + signal(SIGPIPE, SIG_IGN); + + // publish GpuService + sp<GpuService> gpuservice = new GpuService(); + sp<IServiceManager> sm(defaultServiceManager()); + sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false); + + // limit the number of binder threads to 4. + ProcessState::self()->setThreadPoolMaxThreadCount(4); + + // start the thread pool + sp<ProcessState> ps(ProcessState::self()); + ps->startThreadPool(); + ps->giveThreadPoolName(); + IPCThreadState::self()->joinThreadPool(); + + return 0; +} diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 21a9bce273..b37b7fd392 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -2645,7 +2645,7 @@ void CursorInputMapper::configure(nsecs_t when, // Should not happen during first time configuration. ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER"); mParameters.mode = Parameters::MODE_POINTER; - // fall through. + [[fallthrough]]; case Parameters::MODE_POINTER: mSource = AINPUT_SOURCE_MOUSE; mXPrecision = 1.0f; diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp index f1d3726da2..2da2a70c03 100644 --- a/services/inputflinger/host/InputFlinger.cpp +++ b/services/inputflinger/host/InputFlinger.cpp @@ -53,7 +53,7 @@ status_t InputFlinger::dump(int fd, const Vector<String16>& args) { if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDumpPermission, pid, uid)) { result.appendFormat("Permission Denial: " - "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); + "can't dump InputFlinger from pid=%d, uid=%d\n", pid, uid); } else { dumpInternal(result); } diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 320e11f7eb..d1ea84a004 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -50,12 +50,10 @@ cc_defaults { "libtimestats_proto", "libui", "libutils", - "libvulkan", ], static_libs: [ "libserviceutils", "libtrace_proto", - "libvkjson", "libvr_manager", "libvrflinger", ], @@ -106,7 +104,6 @@ filegroup { "EventLog/EventLog.cpp", "EventThread.cpp", "FrameTracker.cpp", - "GpuService.cpp", "Layer.cpp", "LayerProtoHelper.cpp", "LayerRejecter.cpp", diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp index b1ff522de6..d0900e9a5a 100644 --- a/services/surfaceflinger/main_surfaceflinger.cpp +++ b/services/surfaceflinger/main_surfaceflinger.cpp @@ -29,7 +29,6 @@ #include <displayservice/DisplayService.h> #include <hidl/LegacySupport.h> #include <configstore/Utils.h> -#include "GpuService.h" #include "SurfaceFlinger.h" using namespace android; @@ -104,10 +103,6 @@ int main(int, char**) { sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false, IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO); - // publish GpuService - sp<GpuService> gpuservice = new GpuService(); - sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false); - startDisplayService(); // dependency on SF getting registered above struct sched_param param = {0}; diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp index 4b900314d3..d775711ef7 100644 --- a/services/vr/hardware_composer/impl/vr_composer_client.cpp +++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp @@ -19,6 +19,8 @@ #include <hardware/gralloc1.h> #include <log/log.h> +#include <memory> + #include "impl/vr_hwc.h" #include "impl/vr_composer_client.h" @@ -39,7 +41,7 @@ VrComposerClient::~VrComposerClient() {} std::unique_ptr<ComposerCommandEngine> VrComposerClient::createCommandEngine() { - return std::unique_ptr<VrCommandEngine>(new VrCommandEngine(*this)); + return std::make_unique<VrCommandEngine>(*this); } VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client) diff --git a/services/vr/performanced/Android.bp b/services/vr/performanced/Android.bp new file mode 100644 index 0000000000..20301f6ebe --- /dev/null +++ b/services/vr/performanced/Android.bp @@ -0,0 +1,53 @@ +// 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. + +cc_defaults { + name: "performanced_defaults", + static_libs: [ + "libperformance", + "libvr_manager", + ], + shared_libs: [ + "libbinder", + "libbase", + "libcutils", + "liblog", + "libutils", + "libpdx_default_transport", + ], +} + +cc_binary { + name: "performanced", + defaults: ["performanced_defaults"], + srcs: [ + "cpu_set.cpp", + "main.cpp", + "performance_service.cpp", + "task.cpp", + ], + cflags: [ + "-DLOG_TAG=\"performanced\"", + "-DTRACE=0", + "-Wall", + "-Werror", + ], + init_rc: ["performanced.rc"], +} + +cc_test { + name: "performance_service_tests", + defaults: ["performanced_defaults"], + srcs: ["performance_service_tests.cpp"], +} diff --git a/services/vr/performanced/Android.mk b/services/vr/performanced/Android.mk deleted file mode 100644 index a548ef0fac..0000000000 --- a/services/vr/performanced/Android.mk +++ /dev/null @@ -1,52 +0,0 @@ -# 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. - -LOCAL_PATH := $(call my-dir) - -sourceFiles := \ - cpu_set.cpp \ - main.cpp \ - performance_service.cpp \ - task.cpp - -staticLibraries := \ - libperformance \ - libvr_manager - -sharedLibraries := \ - libbinder \ - libbase \ - libcutils \ - liblog \ - libutils \ - libpdx_default_transport \ - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(sourceFiles) -LOCAL_CFLAGS := -DLOG_TAG=\"performanced\" -LOCAL_CFLAGS += -DTRACE=0 -LOCAL_CFLAGS += -Wall -Werror -LOCAL_STATIC_LIBRARIES := $(staticLibraries) -LOCAL_SHARED_LIBRARIES := $(sharedLibraries) -LOCAL_MODULE := performanced -LOCAL_INIT_RC := performanced.rc -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := performance_service_tests.cpp -LOCAL_STATIC_LIBRARIES := $(staticLibraries) libgtest_main -LOCAL_SHARED_LIBRARIES := $(sharedLibraries) -LOCAL_MODULE := performance_service_tests -LOCAL_MODULE_TAGS := optional -include $(BUILD_NATIVE_TEST) diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp index 4065785426..a24c88979a 100644 --- a/services/vr/performanced/performance_service_tests.cpp +++ b/services/vr/performanced/performance_service_tests.cpp @@ -12,16 +12,16 @@ #include <thread> #include <utility> +#include <android-base/strings.h> #include <android-base/unique_fd.h> #include <dvr/performance_client_api.h> #include <gtest/gtest.h> #include <private/android_filesystem_config.h> #include "stdio_filebuf.h" -#include "string_trim.h" #include "unique_file.h" -using android::dvr::Trim; +using android::base::Trim; using android::dvr::UniqueFile; using android::dvr::stdio_filebuf; diff --git a/services/vr/performanced/string_trim.h b/services/vr/performanced/string_trim.h deleted file mode 100644 index 7094e9fdf8..0000000000 --- a/services/vr/performanced/string_trim.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_ -#define ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_ - -#include <functional> -#include <locale> -#include <string> - -namespace android { -namespace dvr { - -// Trims whitespace from the left side of |subject| and returns the result as a -// new string. -inline std::string LeftTrim(std::string subject) { - subject.erase(subject.begin(), - std::find_if(subject.begin(), subject.end(), - std::not1(std::ptr_fun<int, int>(std::isspace)))); - return subject; -} - -// Trims whitespace from the right side of |subject| and returns the result as a -// new string. -inline std::string RightTrim(std::string subject) { - subject.erase(std::find_if(subject.rbegin(), subject.rend(), - std::not1(std::ptr_fun<int, int>(std::isspace))) - .base(), - subject.end()); - return subject; -} - -// Trims whitespace from the both sides of |subject| and returns the result as a -// new string. -inline std::string Trim(std::string subject) { - subject.erase(subject.begin(), - std::find_if(subject.begin(), subject.end(), - std::not1(std::ptr_fun<int, int>(std::isspace)))); - subject.erase(std::find_if(subject.rbegin(), subject.rend(), - std::not1(std::ptr_fun<int, int>(std::isspace))) - .base(), - subject.end()); - return subject; -} - -} // namespace dvr -} // namespace android - -#endif // ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_ diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp index bda1682331..2fc96bf3f5 100644 --- a/services/vr/performanced/task.cpp +++ b/services/vr/performanced/task.cpp @@ -10,10 +10,10 @@ #include <memory> #include <sstream> +#include <android-base/strings.h> #include <android-base/unique_fd.h> #include "stdio_filebuf.h" -#include "string_trim.h" namespace { @@ -102,7 +102,7 @@ std::string Task::GetStatusField(const std::string& field) const { // The status file has lines with the format <field>:<value>. Extract the // value after the colon. - return Trim(line.substr(offset + field.size() + 1)); + return android::base::Trim(line.substr(offset + field.size() + 1)); } } @@ -123,7 +123,7 @@ void Task::ReadStatusFields() { } std::string key = line.substr(0, offset); - std::string value = Trim(line.substr(offset + 1)); + std::string value = android::base::Trim(line.substr(offset + 1)); ALOGD_IF(TRACE, "Task::ReadStatusFields: key=\"%s\" value=\"%s\"", key.c_str(), value.c_str()); @@ -156,7 +156,7 @@ std::string Task::GetCpuSetPath() const { std::string line = ""; std::getline(file_stream, line); - return Trim(line); + return android::base::Trim(line); } else { return ""; } diff --git a/vulkan/api/platform.api b/vulkan/api/platform.api index 41f398d271..a7c4c30b5e 100644 --- a/vulkan/api/platform.api +++ b/vulkan/api/platform.api @@ -56,3 +56,6 @@ type u64 size_t // VK_USE_PLATFORM_XLIB_XRANDR_EXT @internal type u64 RROutput + +// VK_USE_PLATFORM_FUCHSIA +@internal type u32 zx_handle_t
\ No newline at end of file diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api index 57228104e2..e4c50d533f 100644 --- a/vulkan/api/vulkan.api +++ b/vulkan/api/vulkan.api @@ -28,7 +28,7 @@ import platform "platform.api" // API version (major.minor.patch) define VERSION_MAJOR 1 define VERSION_MINOR 1 -define VERSION_PATCH 86 +define VERSION_PATCH 93 // API limits define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256 @@ -85,9 +85,7 @@ define NULL_HANDLE 0 @extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6 @extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_NAME "VK_KHR_wayland_surface" -// 8 -@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_SPEC_VERSION 4 -@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_NAME "VK_KHR_mir_surface" +// 8 - VK_KHR_mir_surface removed // 9 @extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6 @@ -149,6 +147,10 @@ define NULL_HANDLE 0 @extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1 @extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc" +// 29 +@extension("VK_EXT_transform_feedback") define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1 +@extension("VK_EXT_transform_feedback") define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback" + // 34 @extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 @extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count" @@ -501,6 +503,10 @@ define NULL_HANDLE 0 @extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_SPEC_VERSION 1 @extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_EXTENSION_NAME "VK_KHR_bind_memory2" +// 159 +@extension("VK_EXT_image_drm_format_modifier") define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1 +@extension("VK_EXT_image_drm_format_modifier") define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier" + // 161 @extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1 @extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache" @@ -518,8 +524,8 @@ define NULL_HANDLE 0 @extension("VK_NV_shading_rate_image") define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image" // 166 -@extension("VK_NVX_raytracing") define VK_NVX_RAYTRACING_SPEC_VERSION 1 -@extension("VK_NVX_raytracing") define VK_NVX_RAYTRACING_EXTENSION_NAME "VK_NVX_raytracing" +@extension("VK_NV_raytracing") define VK_NV_RAYTRACING_SPEC_VERSION 2 +@extension("VK_NV_raytracing") define VK_NV_RAYTRACING_EXTENSION_NAME "VK_NV_raytracing" // 167 @extension("VK_NV_representative_fragment_test") define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 1 @@ -557,6 +563,10 @@ define NULL_HANDLE 0 @extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1 @extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties" +// 190 +@extension("VK_AMD_memory_overallocation_behavior") define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1 +@extension("VK_AMD_memory_overallocation_behavior") define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior" + // 191 @extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2 @extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor" @@ -597,6 +607,30 @@ define NULL_HANDLE 0 @extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2 @extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model" +// 213 +@extension("VK_EXT_pci_bus_info") define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 1 +@extension("VK_EXT_pci_bus_info") define VK_EXT_PCI_BUS_INFO_EXENSION_NAME "VK_EXT_pci_bus_info" + +// 215 +@extension("VK_FUCHSIA_imagepipe_surface") define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1 +@extension("VK_FUCHSIA_imagepipe_surface") define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface" + +// 222 +@extension("VK_EXT_scalar_block_layout") define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1 +@extension("VK_EXT_scalar_block_layout") define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout" + +// 224 +@extension("VK_GOOGLE_hlsl_functionality1") define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 0 +@extension("VK_GOOGLE_hlsl_functionality1") define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" + +// 225 +@extension("VK_GOOGLE_decorate_string") define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 0 +@extension("VK_GOOGLE_decorate_string") define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string" + +// 247 +@extension("VK_EXT_separate_stencil_usage") define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1 +@extension("VK_EXT_separate_stencil_usage") define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage" + ///////////// // Types // ///////////// @@ -669,7 +703,7 @@ type u32 VkSampleMask @extension("VK_EXT_validation_cache") @nonDispatchHandle type u64 VkValidationCacheEXT // 166 -@extension("VK_NVX_raytracing") @nonDispatchHandle type u64 VkAccelerationStructureNVX +@extension("VK_NV_raytracing") @nonDispatchHandle type u64 VkAccelerationStructureNV ///////////// // Enums // @@ -724,6 +758,9 @@ enum VkImageType { enum VkImageTiling { VK_IMAGE_TILING_OPTIMAL = 0x00000000, VK_IMAGE_TILING_LINEAR = 0x00000001, + + //@extension("VK_EXT_image_drm_format_modifier") // 159 + VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000, } enum VkImageViewType { @@ -767,8 +804,8 @@ enum VkDescriptorType { //@extension("VK_EXT_inline_uniform_block") // 139 VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000, - //@extension("VK_NVX_raytracing") // 166 - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NVX = 1000165000, + //@extension("VK_NV_raytracing") // 166 + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, } enum VkQueryType { @@ -776,8 +813,11 @@ enum VkQueryType { VK_QUERY_TYPE_PIPELINE_STATISTICS = 0x00000001, /// Optional VK_QUERY_TYPE_TIMESTAMP = 0x00000002, - //@extension("VK_NVX_raytracing") // 166 - VK_QUERY_TYPE_COMPACTED_SIZE_NVX = 1000165000, + //@extension("VK_EXT_transform_feedback") // 29 + VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004, + + //@extension("VK_NV_raytracing") // 166 + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, } enum VkBorderColor { @@ -793,8 +833,8 @@ enum VkPipelineBindPoint { VK_PIPELINE_BIND_POINT_GRAPHICS = 0x00000000, VK_PIPELINE_BIND_POINT_COMPUTE = 0x00000001, - //@extension("VK_NVX_raytracing") // 166 - VK_PIPELINE_BIND_POINT_RAYTRACING_NVX = 1000165000, + //@extension("VK_NV_raytracing") // 166 + VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = 1000165000, } enum VkPrimitiveTopology { @@ -819,6 +859,9 @@ enum VkSharingMode { enum VkIndexType { VK_INDEX_TYPE_UINT16 = 0x00000000, VK_INDEX_TYPE_UINT32 = 0x00000001, + + //@extension("VK_NV_raytracing") // 166 + VK_INDEX_TYPE_NONE_NV = 1000165000, } enum VkFilter { @@ -1417,9 +1460,6 @@ enum VkStructureType { //@extension("VK_KHR_wayland_surface") // 7 VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, - //@extension("VK_KHR_mir_surface") // 8 - VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, - //@extension("VK_KHR_android_surface") // 9 VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, @@ -1447,6 +1487,11 @@ enum VkStructureType { VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, + //@extension("VK_EXT_transform_feedback") // 29 + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, + //@extension("VK_AMD_texture_gather_bias_lod") // 42 VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, @@ -1722,6 +1767,14 @@ enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = 1000156004, VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = 1000156005, + //@extension("VK_EXT_image_drm_format_modifier") // 159 + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, + //@extension("VK_KHR_bind_memory2") // 158 VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = 1000157000, VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = 1000157001, @@ -1743,18 +1796,18 @@ enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005, - //@extension("VK_NVX_raytracing") // 166 - VK_STRUCTURE_TYPE_RAYTRACING_PIPELINE_CREATE_INFO_NVX = 1000165000, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NVX = 1000165001, - VK_STRUCTURE_TYPE_GEOMETRY_INSTANCE_NVX = 1000165002, - VK_STRUCTURE_TYPE_GEOMETRY_NVX = 1000165003, - VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NVX = 1000165004, - VK_STRUCTURE_TYPE_GEOMETRY_AABB_NVX = 1000165005, - VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NVX = 1000165006, - VK_STRUCTURE_TYPE_DESCRIPTOR_ACCELERATION_STRUCTURE_INFO_NVX = 1000165007, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NVX = 1000165008, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAYTRACING_PROPERTIES_NVX = 1000165009, - VK_STRUCTURE_TYPE_HIT_SHADER_MODULE_CREATE_INFO_NVX = 1000165010, + //@extension("VK_NV_raytracing") // 166 + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001, + VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003, + VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004, + VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005, + VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, + VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012, //@extension("VK_NV_representative_fragment_test") // 167 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000, @@ -1778,12 +1831,18 @@ enum VkStructureType { //@extension("VK_KHR_shader_atomic_int64") // 181 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000, + //@extension("VK_EXT_calibrated_timestamps") // 185 + VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, + //@extension("VK_KHR_driver_properties") // 197 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000, //@extension("VK_AMD_shader_core_properties") // 186 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, + //@extension("VK_AMD_memory_overallocation_behavior") // 190 + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, + //@extension("VK_EXT_vertex_attribute_divisor") // 191 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, @@ -1795,6 +1854,18 @@ enum VkStructureType { //@extension("VK_KHR_vulkan_memory_model") // 212 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000, + + //@extension("VK_EXT_pci_bus_info") // 213 + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000, + + //@extension("VK_FUCHSIA_imagepipe_surface") // 215 + VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, + + //@extension("VK_EXT_scalar_block_layout") + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = 1000221000, + + //@extension("VK_EXT_separate_stencil_usage") // 247 + VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = 1000246000, } enum VkSubpassContents { @@ -1857,14 +1928,17 @@ enum VkResult { //@extension("VK_KHR_maintenance1") // 70 VK_ERROR_OUT_OF_POOL_MEMORY_KHR = 0xC4642878, // -1000069000 - //@extension("VK_EXT_global_priority") // 175 - VK_ERROR_NOT_PERMITTED_EXT = 0xC4628E4F, // -1000174001 - //@extension("VK_KHR_external_memory") // 73 VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = 0xC4641CBD, // -1000072003 + //@extension("VK_EXT_image_drm_format_modifier") // 159 + VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = 0xC462CCD0, // -1000158000 + //@extension("VK_EXT_descriptor_indexing") // 162 VK_ERROR_FRAGMENTATION_EXT = 0xc462c118, // -1000161000 + + //@extension("VK_EXT_global_priority") // 175 + VK_ERROR_NOT_PERMITTED_EXT = 0xC4628E4F, // -1000174001 } enum VkDynamicState { @@ -1956,8 +2030,8 @@ enum VkObjectType { //@extension("VK_EXT_validation_cache") // 161 VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, - //@extension("VK_NVX_raytracing") // 166 - VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX = 1000165000, + //@extension("VK_NV_raytracing") // 166 + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, } @@ -2080,8 +2154,8 @@ enum VkDebugReportObjectTypeEXT { //@extension("VK_KHR_sampler_ycbcr_conversion") // 157 VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = 1000156000, - //@extension("VK_NVX_raytracing") // 166 - VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX_EXT = 1000165000, + //@extension("VK_NV_raytracing") // 166 + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, } @extension("VK_AMD_rasterization_order") // 19 @@ -2256,22 +2330,36 @@ enum VkCoarseSampleOrderTypeNV { VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3, } -@extension("VK_NVX_raytracing") // 166 -enum VkGeometryTypeNVX { - VK_GEOMETRY_TYPE_TRIANGLES_NVX = 0, - VK_GEOMETRY_TYPE_AABBS_NVX = 1, +@extension("VK_NV_raytracing") // 166 +enum VkRayTracingShaderGroupTypeNV { + VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = 0, + VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = 1, + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = 2, +} + +@extension("VK_NV_raytracing") // 166 +enum VkGeometryTypeNV { + VK_GEOMETRY_TYPE_TRIANGLES_NV = 0, + VK_GEOMETRY_TYPE_AABBS_NV = 1, +} + +@extension("VK_NV_raytracing") // 166 +enum VkAccelerationStructureTypeNV { + VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0, + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1, } -@extension("VK_NVX_raytracing") // 166 -enum VkAccelerationStructureTypeNVX { - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX = 0, - VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX = 1, +@extension("VK_NV_raytracing") // 166 +enum VkCopyAccelerationStructureModeNV { + VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = 0, + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = 1, } -@extension("VK_NVX_raytracing") // 166 -enum VkCopyAccelerationStructureModeNVX { - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX = 0, - VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX = 1, +@extension("VK_NV_raytracing") // 166 +enum VkAccelerationStructureMemoryRequirementsTypeNV { + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2, } @extension("VK_EXT_global_priority") // 175 @@ -2282,6 +2370,21 @@ enum VkQueueGlobalPriorityEXT { VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024, } +@extension("VK_EXT_calibrated_timestamps") // 185 +enum VkTimeDomainEXT { + VK_TIME_DOMAIN_DEVICE_EXT = 0, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3, +} + +@extension("VK_AMD_memory_overallocation_behavior") // 190 +enum VkMemoryOverallocationBehaviorAMD { + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2, +} + @extension("VK_KHR_driver_properties") // 197 enum VkDriverIdKHR { VK_DRIVER_ID_AMD_PROPRIETARY_KHR = 1, @@ -2293,6 +2396,7 @@ enum VkDriverIdKHR { VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = 7, VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = 8, VK_DRIVER_ID_ARM_PROPRIETARY_KHR = 9, + VK_DRIVER_ID_GOOGLE_PASTEL_KHR = 10, } ///////////////// @@ -2370,9 +2474,14 @@ bitfield VkAccessFlagBits { //@extension("VK_NV_shading_rate_image") // 165 VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000, - //@extension("VK_NVX_raytracing") // 166 - VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NVX = 0x00200000, - VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVX = 0x00400000, + //@extension("VK_NV_raytracing") // 166 + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000, + VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000, + + //@extension("VK_EXT_transform_feedback") // 29 + VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000, } /// Buffer usage flags @@ -2391,8 +2500,12 @@ bitfield VkBufferUsageFlagBits { //@extension("VK_EXT_conditional_rendering") // 82 VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200, - //@extension("VK_NVX_raytracing") // 166 - VK_BUFFER_USAGE_RAYTRACING_BIT_NVX = 0x00000400, + //@extension("VK_NV_raytracing") // 166 + VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = 0x00000400, + + //@extension("VK_EXT_transform_feedback") // 29 + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800, + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000, } /// Buffer creation flags @@ -2419,13 +2532,13 @@ bitfield VkShaderStageFlagBits { VK_SHADER_STAGE_ALL = 0x7FFFFFFF, - //@extension("VK_NVX_raytracing") // 166 - VK_SHADER_STAGE_RAYGEN_BIT_NVX = 0x00000100, - VK_SHADER_STAGE_ANY_HIT_BIT_NVX = 0x00000200, - VK_SHADER_STAGE_CLOSEST_HIT_BIT_NVX = 0x00000400, - VK_SHADER_STAGE_MISS_BIT_NVX = 0x00000800, - VK_SHADER_STAGE_INTERSECTION_BIT_NVX = 0x00001000, - VK_SHADER_STAGE_CALLABLE_BIT_NVX = 0x00002000, + //@extension("VK_NV_raytracing") // 166 + VK_SHADER_STAGE_RAYGEN_BIT_NV = 0x00000100, + VK_SHADER_STAGE_ANY_HIT_BIT_NV = 0x00000200, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = 0x00000400, + VK_SHADER_STAGE_MISS_BIT_NV = 0x00000800, + VK_SHADER_STAGE_INTERSECTION_BIT_NV = 0x00001000, + VK_SHADER_STAGE_CALLABLE_BIT_NV = 0x00002000, //@extension("VK_NV_mesh_shader") // 203 VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040, @@ -2523,8 +2636,8 @@ bitfield VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 0x00000008, VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = 0x00000010, - //@extension("VK_NVX_raytracing") // 166 - VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NVX = 0x00000020, + //@extension("VK_NV_raytracing") // 166 + VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020, } /// Color component flags @@ -2666,6 +2779,12 @@ bitfield VkImageAspectFlagBits { VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = 0x00000010, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = 0x00000020, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = 0x00000040, + + //@extension("VK_EXT_transform_feedback") // 29 + VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080, + VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100, + VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200, + VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400, } /// Sparse memory bind flags @@ -2713,12 +2832,16 @@ bitfield VkPipelineStageFlagBits { //@extension("VK_NV_shading_rate_image") // 165 VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000, - //@extension("VK_NVX_raytracing") // 166 - VK_PIPELINE_STAGE_RAYTRACING_BIT_NVX = 0x00200000, + //@extension("VK_NV_raytracing") // 166 + VK_PIPELINE_STAGE_RAY_TRACING_BIT_NV = 0x00200000, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000, //@extension("VK_NV_mesh_shader") // 203 VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000, + + //@extension("VK_EXT_transform_feedback") // 29 + VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000, } /// Render pass attachment description flags @@ -3113,12 +3236,6 @@ type VkFlags VkWaylandSurfaceCreateFlagsKHR //bitfield VkWaylandSurfaceCreateFlagBitsKHR { //} -@extension("VK_KHR_mir_surface") // 8 -type VkFlags VkMirSurfaceCreateFlagsKHR -//@extension("VK_KHR_mir_surface") // 8 -//bitfield VkMirSurfaceCreateFlagBitsKHR { -//} - @extension("VK_KHR_android_surface") // 9 type VkFlags VkAndroidSurfaceCreateFlagsKHR //@extension("VK_KHR_android_surface") // 9 @@ -3149,6 +3266,12 @@ bitfield VkDebugReportFlagBitsEXT { VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010, } +@extension("VK_EXT_transform_feedback") // 29 +type VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT +//@extension("VK_EXT_transform_feedback") // 29 +//bitfield VkPipelineRasterizationStateStreamCreateFlagBitsEXT { +//} + @extension("VK_NV_external_memory_capabilities") // 56 type VkFlags VkExternalMemoryHandleTypeFlagsNV @extension("VK_NV_external_memory_capabilities") // 56 @@ -3397,35 +3520,41 @@ bitfield VkDescriptorBindingFlagBitsEXT { VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = 0x00000008, } -@extension("VK_NVX_raytracing") // 166 -type VkFlags VkGeometryFlagsNVX -@extension("VK_NVX_raytracing") // 166 -bitfield VkGeometryFlagBitsNVX { - VK_GEOMETRY_OPAQUE_BIT_NVX = 0x00000001, - VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NVX = 0x00000002, +@extension("VK_NV_raytracing") // 166 +type VkFlags VkGeometryFlagsNV +@extension("VK_NV_raytracing") // 166 +bitfield VkGeometryFlagBitsNV { + VK_GEOMETRY_OPAQUE_BIT_NV = 0x00000001, + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = 0x00000002, } -@extension("VK_NVX_raytracing") // 166 -type VkFlags VkGeometryInstanceFlagsNVX -@extension("VK_NVX_raytracing") // 166 -bitfield VkGeometryInstanceFlagBitsNVX { - VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NVX = 0x00000001, - VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_FLIP_WINDING_BIT_NVX = 0x00000002, - VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NVX = 0x00000004, - VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NVX = 0x00000008, +@extension("VK_NV_raytracing") // 166 +type VkFlags VkGeometryInstanceFlagsNV +@extension("VK_NV_raytracing") // 166 +bitfield VkGeometryInstanceFlagBitsNV { + VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = 0x00000001, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002, + VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = 0x00000004, + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = 0x00000008, } -@extension("VK_NVX_raytracing") // 166 -type VkFlags VkBuildAccelerationStructureFlagsNVX -@extension("VK_NVX_raytracing") // 166 -bitfield VkBuildAccelerationStructureFlagBitsNVX { - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NVX = 0x00000001, - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NVX = 0x00000002, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NVX = 0x00000004, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NVX = 0x00000008, - VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NVX = 0x00000010, +@extension("VK_NV_raytracing") // 166 +type VkFlags VkBuildAccelerationStructureFlagsNV +@extension("VK_NV_raytracing") // 166 +bitfield VkBuildAccelerationStructureFlagBitsNV { + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = 0x00000001, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = 0x00000002, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = 0x00000004, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = 0x00000008, + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = 0x00000010, } +@extension("VK_FUCHSIA_imagepipe_surface") // 215 +type VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA +//@extension("VK_FUCHSIA_imagepipe_surface") // 215 +//bitfield VkImagePipeSurfaceCreateFlagBitsFUCHSIA { +//} + ////////////////// // Structures // ////////////////// @@ -5237,15 +5366,6 @@ class VkWaylandSurfaceCreateInfoKHR { platform.wl_surface* surface } -@extension("VK_KHR_mir_surface") // 8 -class VkMirSurfaceCreateInfoKHR { - VkStructureType sType - const void* pNext - VkMirSurfaceCreateFlagsKHR flags - platform.MirConnection* connection - platform.MirSurface* mirSurface -} - @extension("VK_KHR_android_surface") // 9 class VkAndroidSurfaceCreateInfoKHR { VkStructureType sType @@ -5360,6 +5480,38 @@ class VkDedicatedAllocationMemoryAllocateInfoNV { VkBuffer buffer } +@extension("VK_EXT_transform_feedback") // 29 +class VkPhysicalDeviceTransformFeedbackFeaturesEXT { + VkStructureType sType + void* pNext + VkBool32 transformFeedback + VkBool32 geometryStreams +} + +@extension("VK_EXT_transform_feedback") // 29 +class VkPhysicalDeviceTransformFeedbackPropertiesEXT { + VkStructureType sType + void* pNext + u32 maxTransformFeedbackStreams + u32 maxTransformFeedbackBuffers + VkDeviceSize maxTransformFeedbackBufferSize + u32 maxTransformFeedbackStreamDataSize + u32 maxTransformFeedbackBufferDataSize + u32 maxTransformFeedbackBufferDataStride + VkBool32 transformFeedbackQueries + VkBool32 transformFeedbackStreamsLinesTriangles + VkBool32 transformFeedbackRasterizationStreamSelect + VkBool32 transformFeedbackDraw +} + +@extension("VK_EXT_transform_feedback") // 29 +class VkPipelineRasterizationStateStreamCreateInfoEXT { + VkStructureType sType + const void* pNext + VkPipelineRasterizationStateStreamCreateFlagsEXT flags + u32 rasterizationStream +} + @extension("VK_AMD_texture_gather_bias_lod") // 42 class VkTextureLODGatherFormatPropertiesAMD { VkStructureType sType @@ -6599,7 +6751,7 @@ class VkDebugUtilsMessengerCreateInfoEXT { const void* pNext VkDebugUtilsMessengerCreateFlagsEXT flags VkDebugUtilsMessageSeverityFlagsEXT messageSeverity - VkDebugUtilsMessageTypeFlagsEXT messageType + VkDebugUtilsMessageTypeFlagsEXT messageTypes PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback void* pUserData } @@ -6925,6 +7077,55 @@ class VkBindImageMemoryInfoKHR { VkDeviceSize memoryOffset } +@extension("VK_EXT_image_drm_format_modifier") // 159 +class VkDrmFormatModifierPropertiesEXT { + u64 drmFormatModifier + u32 drmFormatModifierPlaneCount + VkFormatFeatureFlags drmFormatModifierTilingFeatures +} + +@extension("VK_EXT_image_drm_format_modifier") // 159 +class VkDrmFormatModifierPropertiesListEXT { + VkStructureType sType + void* pNext + u32 drmFormatModifierCount + VkDrmFormatModifierPropertiesEXT* pDrmFormatModifierProperties +} + +@extension("VK_EXT_image_drm_format_modifier") // 159 +class VkPhysicalDeviceImageDrmFormatModifierInfoEXT { + VkStructureType sType + const void* pNext + u64 drmFormatModifier + VkSharingMode sharingMode + u32 queueFamilyIndexCount + const u32* pQueueFamilyIndices +} + +@extension("VK_EXT_image_drm_format_modifier") // 159 +class VkImageDrmFormatModifierListCreateInfoEXT { + VkStructureType sType + const void* pNext + u32 drmFormatModifierCount + const u64* pDrmFormatModifiers +} + +@extension("VK_EXT_image_drm_format_modifier") // 159 +class VkImageDrmFormatModifierExplicitCreateInfoEXT { + VkStructureType sType + const void* pNext + u64 drmFormatModifier + u32 drmFormatModifierPlaneCount + const VkSubresourceLayout* pPlaneLayouts +} + +@extension("VK_EXT_image_drm_format_modifier") // 159 +class VkImageDrmFormatModifierPropertiesEXT { + VkStructureType sType + void* pNext + u64 drmFormatModifier +} + @extension("VK_EXT_validation_cache") // 161 class VkValidationCacheCreateInfoEXT { VkStructureType sType @@ -7075,22 +7276,34 @@ class VkPipelineViewportCoarseSampleOrderStateCreateInfoNV { const VkCoarseSampleOrderCustomNV* pCustomSampleOrders } -@extension("VK_NVX_raytracing") // 166 -class VkRaytracingPipelineCreateInfoNVX { - VkStructureType sType - const void* pNext - VkPipelineCreateFlags flags - u32 stageCount - const VkPipelineShaderStageCreateInfo* pStages - const u32* pGroupNumbers - u32 maxRecursionDepth - VkPipelineLayout layout - VkPipeline basePipelineHandle - s32 basePipelineIndex -} - -@extension("VK_NVX_raytracing") // 166 -class VkGeometryTrianglesNVX { +@extension("VK_NV_raytracing") // 166 +class VkRayTracingShaderGroupCreateInfoNV { + VkStructureType sType + const void* pNext + VkRayTracingShaderGroupTypeNV type + u32 generalShader + u32 closestHitShader + u32 anyHitShader + u32 intersectionShader +} + +@extension("VK_NV_raytracing") // 166 +class VkRayTracingPipelineCreateInfoNV { + VkStructureType sType + const void* pNext + VkPipelineCreateFlags flags + u32 stageCount + const VkPipelineShaderStageCreateInfo* pStages + u32 groupCount + const VkRayTracingShaderGroupCreateInfoNV* pGroups + u32 maxRecursionDepth + VkPipelineLayout layout + VkPipeline basePipelineHandle + s32 basePipelineIndex +} + +@extension("VK_NV_raytracing") // 166 +class VkGeometryTrianglesNV { VkStructureType sType const void* pNext VkBuffer vertexData @@ -7106,8 +7319,8 @@ class VkGeometryTrianglesNVX { VkDeviceSize transformOffset } -@extension("VK_NVX_raytracing") // 166 -class VkGeometryAABBNVX { +@extension("VK_NV_raytracing") // 166 +class VkGeometryAABBNV { VkStructureType sType const void* pNext VkBuffer aabbData @@ -7116,66 +7329,79 @@ class VkGeometryAABBNVX { VkDeviceSize offset } -@extension("VK_NVX_raytracing") // 166 -class VkGeometryDataNVX { - VkGeometryTrianglesNVX triangles - VkGeometryAABBNVX aabbs +@extension("VK_NV_raytracing") // 166 +class VkGeometryDataNV { + VkGeometryTrianglesNV triangles + VkGeometryAABBNV aabbs } -@extension("VK_NVX_raytracing") // 166 -class VkGeometryNVX { +@extension("VK_NV_raytracing") // 166 +class VkGeometryNV { VkStructureType sType const void* pNext - VkGeometryTypeNVX geometryType - VkGeometryDataNVX geometry - VkGeometryFlagsNVX flags + VkGeometryTypeNV geometryType + VkGeometryDataNV geometry + VkGeometryFlagsNV flags } -@extension("VK_NVX_raytracing") // 166 -class VkAccelerationStructureCreateInfoNVX { +@extension("VK_NV_raytracing") // 166 +class VkAccelerationStructureInfoNV { VkStructureType sType const void* pNext - VkAccelerationStructureTypeNVX type - VkBuildAccelerationStructureFlagsNVX flags - VkDeviceSize compactedSize + VkAccelerationStructureTypeNV type + VkBuildAccelerationStructureFlagsNV flags u32 instanceCount u32 geometryCount - const VkGeometryNVX* pGeometries + const VkGeometryNV* pGeometries } -@extension("VK_NVX_raytracing") // 166 -class VkBindAccelerationStructureMemoryInfoNVX { +@extension("VK_NV_raytracing") // 166 +class VkAccelerationStructureCreateInfoNV { VkStructureType sType const void* pNext - VkAccelerationStructureNVX accelerationStructure + VkDeviceSize compactedSize + VkAccelerationStructureInfoNV info +} + +@extension("VK_NV_raytracing") // 166 +class VkBindAccelerationStructureMemoryInfoNV { + VkStructureType sType + const void* pNext + VkAccelerationStructureNV accelerationStructure VkDeviceMemory memory VkDeviceSize memoryOffset u32 deviceIndexCount const u32* pDeviceIndices } -@extension("VK_NVX_raytracing") // 166 -class VkDescriptorAccelerationStructureInfoNVX { +@extension("VK_NV_raytracing") // 166 +class VkDescriptorAccelerationStructureInfoNV { VkStructureType sType const void* pNext u32 accelerationStructureCount - const VkAccelerationStructureNVX* pAccelerationStructures + const VkAccelerationStructureNV* pAccelerationStructures } -@extension("VK_NVX_raytracing") // 166 -class VkAccelerationStructureMemoryRequirementsInfoNVX { +@extension("VK_NV_raytracing") // 166 +class VkAccelerationStructureMemoryRequirementsInfoNV { VkStructureType sType const void* pNext - VkAccelerationStructureNVX accelerationStructure + VkAccelerationStructureMemoryRequirementsTypeNV type + VkAccelerationStructureNV accelerationStructure } -@extension("VK_NVX_raytracing") // 166 -class VkPhysicalDeviceRaytracingPropertiesNVX { +@extension("VK_NV_raytracing") // 166 +class VkPhysicalDeviceRaytracingPropertiesNV { VkStructureType sType void* pNext - u32 shaderHeaderSize + u32 shaderGroupHandleSize u32 maxRecursionDepth - u32 maxGeometryCount + u32 maxShaderGroupStride + u32 shaderGroupBaseAlignment + u64 maxGeometryCount + u64 maxInstanceCount + u64 maxTriangleCount + u32 maxDescriptorSetAccelerationStructures } @extension("VK_NV_representative_fragment_test") // 167 @@ -7253,6 +7479,13 @@ class VkPhysicalDeviceShaderAtomicInt64FeaturesKHR { VkBool32 shaderSharedInt64Atomics } +@extension("VK_EXT_calibrated_timestamps") // 185 +class VkCalibratedTimestampInfoEXT { + VkStructureType sType + const void* pNext + VkTimeDomainEXT timeDomain +} + @extension("VK_AMD_shader_core_properties") // 186 class VkPhysicalDeviceShaderCorePropertiesAMD { VkStructureType sType @@ -7273,6 +7506,13 @@ class VkPhysicalDeviceShaderCorePropertiesAMD { u32 vgprAllocationGranularity } +@extension("VK_AMD_memory_overallocation_behavior") // 190 +class VkDeviceMemoryOverallocationCreateInfoAMD { + VkStructureType sType + const void* pNext + VkMemoryOverallocationBehaviorAMD overallocationBehavior +} + @extension("VK_EXT_vertex_attribute_divisor") // 191 class VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT { VkStructureType sType @@ -7314,7 +7554,7 @@ class VkConformanceVersionKHR { class VkPhysicalDeviceDriverPropertiesKHR { VkStructureType sType void* pNext - u32 driverID + VkDriverIdKHR driverID char[VK_MAX_DRIVER_NAME_SIZE_KHR] driverName char[VK_MAX_DRIVER_INFO_SIZE_KHR] driverInfo VkConformanceVersionKHR conformanceVersion @@ -7413,6 +7653,38 @@ class VkPhysicalDeviceVulkanMemoryModelFeaturesKHR { VkBool32 vulkanMemoryModelDeviceScope } +@extension("VK_EXT_pci_bus_info") // 213 +class VkPhysicalDevicePCIBusInfoPropertiesEXT { + VkStructureType sType + void* pNext + u16 pciDomain + u8 pciBus + u8 pciDevice + u8 pciFunction +} + +@extension("VK_FUCHSIA_imagepipe_surface") // 215 +class VkImagePipeSurfaceCreateInfoFUCHSIA { + VkStructureType sType + const void* pNext + VkImagePipeSurfaceCreateFlagsFUCHSIA flags + platform.zx_handle_t imagePipeHandle +} + +@extension("VK_EXT_scalar_block_layout") // 222 +class VkPhysicalDeviceScalarBlockLayoutFeaturesEXT { + VkStructureType sType + void* pNext + VkBool32 scalarBlockLayout +} + +@extension("VK_EXT_separate_stencil_usage") // 247 +class VkImageStencilUsageCreateInfoEXT { + VkStructureType sType + const void* pNext + VkImageUsageFlags stencilUsage +} + //////////////// // Commands // @@ -10171,25 +10443,6 @@ cmd VkBool32 vkGetPhysicalDeviceWaylandPresentationSupportKHR( return ? } -@extension("VK_KHR_mir_surface") // 8 -cmd VkResult vkCreateMirSurfaceKHR( - VkInstance instance, - const VkMirSurfaceCreateInfoKHR* pCreateInfo, - const VkAllocationCallbacks* pAllocator, - VkSurfaceKHR* pSurface) { - instanceObject := GetInstance(instance) - return ? -} - -@extension("VK_KHR_mir_surface") // 8 -cmd VkBool32 vkGetPhysicalDeviceMirPresentationSupportKHR( - VkPhysicalDevice physicalDevice, - u32 queueFamilyIndex, - platform.MirConnection* connection) { - physicalDeviceObject := GetPhysicalDevice(physicalDevice) - return ? -} - @extension("VK_KHR_android_surface") // 9 cmd VkResult vkCreateAndroidSurfaceKHR( VkInstance instance, @@ -10334,6 +10587,62 @@ cmd void vkCmdDebugMarkerInsertEXT( const VkDebugMarkerMarkerInfoEXT* pMarkerInfo) { } +@extension("VK_EXT_transform_feedback") // 29 +cmd void vkCmdBindTransformFeedbackBuffersEXT( + VkCommandBuffer commandBuffer, + u32 firstBinding, + u32 bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes) { +} + +@extension("VK_EXT_transform_feedback") // 29 +cmd void vkCmdBeginTransformFeedbackEXT( + VkCommandBuffer commandBuffer, + u32 firstCounterBuffer, + u32 counterBufferCount, + const VkBuffer* pCounterBuffers, + const VkDeviceSize* pCounterBufferOffsets) { +} + +@extension("VK_EXT_transform_feedback") // 29 +cmd void vkCmdEndTransformFeedbackEXT( + VkCommandBuffer commandBuffer, + u32 firstCounterBuffer, + u32 counterBufferCount, + const VkBuffer* pCounterBuffers, + const VkDeviceSize* pCounterBufferOffsets) { +} + +@extension("VK_EXT_transform_feedback") // 29 +cmd void vkCmdBeginQueryIndexedEXT( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + u32 query, + VkQueryControlFlags flags, + u32 index) { +} + +@extension("VK_EXT_transform_feedback") // 29 +cmd void vkCmdEndQueryIndexedEXT( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + u32 query, + u32 index) { +} + +@extension("VK_EXT_transform_feedback") // 29 +cmd void vkCmdDrawIndirectByteCountEXT( + VkCommandBuffer commandBuffer, + u32 instanceCount, + u32 firstInstance, + VkBuffer counterBuffer, + VkDeviceSize counterBufferOffset, + u32 counterOffset, + u32 vertexStride) { +} + @extension("VK_AMD_draw_indirect_count") // 34 cmd void vkCmdDrawIndirectCountAMD( VkCommandBuffer commandBuffer, @@ -11128,6 +11437,14 @@ cmd VkResult vkBindImageMemory2KHR( return ? } +@extension("VK_EXT_image_drm_format_modifier") // 159 +cmd VkResult vkGetImageDrmFormatModifierPropertiesEXT( + VkDevice device, + VkImage image, + VkImageDrmFormatModifierPropertiesEXT* pProperties) { + return ? +} + @extension("VK_EXT_validation_cache") // 161 cmd VkResult vkCreateValidationCacheEXT( VkDevice device, @@ -11185,71 +11502,60 @@ cmd void vkCmdSetCoarseSampleOrderNV( const VkCoarseSampleOrderCustomNV* pCustomSampleOrders) { } -@extension("VK_NVX_raytracing") // 166 -cmd VkResult vkCreateAccelerationStructureNVX( +@extension("VK_NV_raytracing") // 166 +cmd VkResult vkCreateAccelerationStructureNV( VkDevice device, - const VkAccelerationStructureCreateInfoNVX* pCreateInfo, + const VkAccelerationStructureCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, - VkAccelerationStructureNVX* pAccelerationStructure) { + VkAccelerationStructureNV* pAccelerationStructure) { return ? } -@extension("VK_NVX_raytracing") // 166 -cmd void vkDestroyAccelerationStructureNVX( +@extension("VK_NV_raytracing") // 166 +cmd void vkDestroyAccelerationStructureNV( VkDevice device, - VkAccelerationStructureNVX accelerationStructure, + VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks* pAllocator) { } -@extension("VK_NVX_raytracing") // 166 -cmd void vkGetAccelerationStructureMemoryRequirementsNVX( - VkDevice device, - const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, - VkMemoryRequirements2KHR* pMemoryRequirements) { -} - -@extension("VK_NVX_raytracing") // 166 -cmd void vkGetAccelerationStructureScratchMemoryRequirementsNVX( +@extension("VK_NV_raytracing") // 166 +cmd void vkGetAccelerationStructureMemoryRequirementsNV( VkDevice device, - const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, + const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements) { } -@extension("VK_NVX_raytracing") // 166 -cmd VkResult vkBindAccelerationStructureMemoryNVX( +@extension("VK_NV_raytracing") // 166 +cmd VkResult vkBindAccelerationStructureMemoryNV( VkDevice device, u32 bindInfoCount, - const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos) { + const VkBindAccelerationStructureMemoryInfoNV* pBindInfos) { return ? } -@extension("VK_NVX_raytracing") // 166 -cmd void vkCmdBuildAccelerationStructureNVX( +@extension("VK_NV_raytracing") // 166 +cmd void vkCmdBuildAccelerationStructureNV( VkCommandBuffer commandBuffer, - VkAccelerationStructureTypeNVX type, - u32 instanceCount, + const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, - u32 geometryCount, - const VkGeometryNVX* pGeometries, - VkBuildAccelerationStructureFlagsNVX flags, VkBool32 update, - VkAccelerationStructureNVX dst, - VkAccelerationStructureNVX src, + VkAccelerationStructureNV dst, + VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset) { } -@extension("VK_NVX_raytracing") // 166 -cmd void vkCmdCopyAccelerationStructureNVX( +@extension("VK_NV_raytracing") // 166 +cmd void vkCmdCopyAccelerationStructureNV( VkCommandBuffer commandBuffer, - VkAccelerationStructureNVX dst, - VkAccelerationStructureNVX src, - VkCopyAccelerationStructureModeNVX mode) { + VkAccelerationStructureNV dst, + VkAccelerationStructureNV src, + VkCopyAccelerationStructureModeNV mode) { } -@extension("VK_NVX_raytracing") // 166 -cmd void vkCmdTraceRaysNVX( +@extension("VK_NV_raytracing") // 166 +cmd void vkCmdTraceRaysNV( VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, @@ -11259,23 +11565,27 @@ cmd void vkCmdTraceRaysNVX( VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, + VkBuffer callableShaderBindingTableBuffer, + VkDeviceSize callableShaderBindingOffset, + VkDeviceSize callableShaderBindingStride, u32 width, - u32 height) { + u32 height, + u32 depth) { } -@extension("VK_NVX_raytracing") // 166 -cmd VkResult vkCreateRaytracingPipelinesNVX( +@extension("VK_NV_raytracing") // 166 +cmd VkResult vkCreateRaytracingPipelinesNV( VkDevice device, VkPipelineCache pipelineCache, u32 createInfoCount, - const VkRaytracingPipelineCreateInfoNVX* pCreateInfos, + const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines) { return ? } -@extension("VK_NVX_raytracing") // 166 -cmd VkResult vkGetRaytracingShaderHandlesNVX( +@extension("VK_NV_raytracing") // 166 +cmd VkResult vkGetRaytracingShaderHandlesNV( VkDevice device, VkPipeline pipeline, u32 firstGroup, @@ -11285,26 +11595,27 @@ cmd VkResult vkGetRaytracingShaderHandlesNVX( return ? } -@extension("VK_NVX_raytracing") // 166 -cmd VkResult vkGetAccelerationStructureHandleNVX( +@extension("VK_NV_raytracing") // 166 +cmd VkResult vkGetAccelerationStructureHandleNV( VkDevice device, - VkAccelerationStructureNVX accelerationStructure, + VkAccelerationStructureNV accelerationStructure, platform.size_t dataSize, void* pData) { return ? } -@extension("VK_NVX_raytracing") // 166 -cmd void vkCmdWriteAccelerationStructurePropertiesNVX( +@extension("VK_NV_raytracing") // 166 +cmd void vkCmdWriteAccelerationStructurePropertiesNV( VkCommandBuffer commandBuffer, - VkAccelerationStructureNVX accelerationStructure, + u32 accelerationStructureCount, + const VkAccelerationStructureNV* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, - u32 query) { + u32 firstQuery) { } -@extension("VK_NVX_raytracing") // 166 -cmd VkResult vkCompileDeferredNVX( +@extension("VK_NV_raytracing") // 166 +cmd VkResult vkCompileDeferredNV( VkDevice device, VkPipeline pipeline, u32 shader) { @@ -11358,6 +11669,24 @@ cmd void vkCmdWriteBufferMarkerAMD( u32 marker) { } +@extension("VK_EXT_calibrated_timestamps") // 185 +cmd VkResult vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( + VkPhysicalDevice physicalDevice, + u32* pTimeDomainCount, + VkTimeDomainEXT* pTimeDomains) { + return ? +} + +@extension("VK_EXT_calibrated_timestamps") // 185 +cmd VkResult vkGetCalibratedTimestampsEXT( + VkDevice device, + u32 timestampCount, + const VkCalibratedTimestampInfoEXT* pTimestampInfos, + u64* pTimestamps, + u64* pMaxDeviation) { + return ? +} + @extension("VK_NV_mesh_shader") // 203 cmd void vkCmdDrawMeshTasksNV( VkCommandBuffer commandBuffer, @@ -11406,6 +11735,15 @@ cmd void vkGetQueueCheckpointDataNV( VkCheckpointDataNV* pCheckpointData) { } +@extension("VK_FUCHSIA_imagepipe_surface") // 215 +cmd VkResult vkCreateImagePipeSurfaceFUCHSIA( + VkInstance instance, + const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface) { + return ? +} + //////////////// // Validation // diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h index d05c8490a5..77da63783e 100644 --- a/vulkan/include/vulkan/vulkan.h +++ b/vulkan/include/vulkan/vulkan.h @@ -24,6 +24,10 @@ #include "vulkan_android.h" #endif +#ifdef VK_USE_PLATFORM_FUCHSIA +#include <zircon/types.h> +#include "vulkan_fuchsia.h" +#endif #ifdef VK_USE_PLATFORM_IOS_MVK #include "vulkan_ios.h" @@ -35,12 +39,6 @@ #endif -#ifdef VK_USE_PLATFORM_MIR_KHR -#include <mir_toolkit/client_types.h> -#include "vulkan_mir.h" -#endif - - #ifdef VK_USE_PLATFORM_VI_NN #include "vulkan_vi.h" #endif diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h index 39f4dc6f05..35c06649aa 100644 --- a/vulkan/include/vulkan/vulkan_core.h +++ b/vulkan/include/vulkan/vulkan_core.h @@ -43,11 +43,10 @@ extern "C" { #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) // Version of this file -#define VK_HEADER_VERSION 86 +#define VK_HEADER_VERSION 93 #define VK_NULL_HANDLE 0 - #define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; @@ -60,7 +59,6 @@ extern "C" { #define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; #endif #endif - typedef uint32_t VkFlags; @@ -147,6 +145,7 @@ typedef enum VkResult { VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001, VK_ERROR_VALIDATION_FAILED_EXT = -1000011001, VK_ERROR_INVALID_SHADER_NV = -1000012000, + VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000, VK_ERROR_FRAGMENTATION_EXT = -1000161000, VK_ERROR_NOT_PERMITTED_EXT = -1000174001, VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY, @@ -286,7 +285,6 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000, VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000, VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, - VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000, VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000, VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000, @@ -297,6 +295,9 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000, VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001, VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001, + VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002, VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000, VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000, @@ -398,6 +399,12 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002, VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000, VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000, + VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158001, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004, + VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005, VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000, VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = 1000161000, @@ -409,17 +416,17 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002, VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005, - VK_STRUCTURE_TYPE_RAYTRACING_PIPELINE_CREATE_INFO_NVX = 1000165000, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NVX = 1000165001, - VK_STRUCTURE_TYPE_GEOMETRY_INSTANCE_NVX = 1000165002, - VK_STRUCTURE_TYPE_GEOMETRY_NVX = 1000165003, - VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NVX = 1000165004, - VK_STRUCTURE_TYPE_GEOMETRY_AABB_NVX = 1000165005, - VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NVX = 1000165006, - VK_STRUCTURE_TYPE_DESCRIPTOR_ACCELERATION_STRUCTURE_INFO_NVX = 1000165007, - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NVX = 1000165008, - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAYTRACING_PROPERTIES_NVX = 1000165009, - VK_STRUCTURE_TYPE_HIT_SHADER_MODULE_CREATE_INFO_NVX = 1000165010, + VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001, + VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003, + VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004, + VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005, + VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006, + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009, + VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011, + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000, VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001, VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000, @@ -428,7 +435,9 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000, + VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000, + VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000, VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002, @@ -443,6 +452,10 @@ typedef enum VkStructureType { VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000, VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000, + VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = 1000221000, + VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = 1000246000, VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT, VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES, @@ -811,6 +824,7 @@ typedef enum VkImageType { typedef enum VkImageTiling { VK_IMAGE_TILING_OPTIMAL = 0, VK_IMAGE_TILING_LINEAR = 1, + VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000, VK_IMAGE_TILING_BEGIN_RANGE = VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_TILING_END_RANGE = VK_IMAGE_TILING_LINEAR, VK_IMAGE_TILING_RANGE_SIZE = (VK_IMAGE_TILING_LINEAR - VK_IMAGE_TILING_OPTIMAL + 1), @@ -833,7 +847,8 @@ typedef enum VkQueryType { VK_QUERY_TYPE_OCCLUSION = 0, VK_QUERY_TYPE_PIPELINE_STATISTICS = 1, VK_QUERY_TYPE_TIMESTAMP = 2, - VK_QUERY_TYPE_COMPACTED_SIZE_NVX = 1000165000, + VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004, + VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000, VK_QUERY_TYPE_BEGIN_RANGE = VK_QUERY_TYPE_OCCLUSION, VK_QUERY_TYPE_END_RANGE = VK_QUERY_TYPE_TIMESTAMP, VK_QUERY_TYPE_RANGE_SIZE = (VK_QUERY_TYPE_TIMESTAMP - VK_QUERY_TYPE_OCCLUSION + 1), @@ -1163,7 +1178,7 @@ typedef enum VkDescriptorType { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10, VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000, - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NVX = 1000165000, + VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER, VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1), @@ -1192,7 +1207,7 @@ typedef enum VkAttachmentStoreOp { typedef enum VkPipelineBindPoint { VK_PIPELINE_BIND_POINT_GRAPHICS = 0, VK_PIPELINE_BIND_POINT_COMPUTE = 1, - VK_PIPELINE_BIND_POINT_RAYTRACING_NVX = 1000165000, + VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = 1000165000, VK_PIPELINE_BIND_POINT_BEGIN_RANGE = VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_END_RANGE = VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RANGE_SIZE = (VK_PIPELINE_BIND_POINT_COMPUTE - VK_PIPELINE_BIND_POINT_GRAPHICS + 1), @@ -1211,6 +1226,7 @@ typedef enum VkCommandBufferLevel { typedef enum VkIndexType { VK_INDEX_TYPE_UINT16 = 0, VK_INDEX_TYPE_UINT32 = 1, + VK_INDEX_TYPE_NONE_NV = 1000165000, VK_INDEX_TYPE_BEGIN_RANGE = VK_INDEX_TYPE_UINT16, VK_INDEX_TYPE_END_RANGE = VK_INDEX_TYPE_UINT32, VK_INDEX_TYPE_RANGE_SIZE = (VK_INDEX_TYPE_UINT32 - VK_INDEX_TYPE_UINT16 + 1), @@ -1264,7 +1280,7 @@ typedef enum VkObjectType { VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001, VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000, VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000, - VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX = 1000165000, + VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000, VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, VK_OBJECT_TYPE_BEGIN_RANGE = VK_OBJECT_TYPE_UNKNOWN, @@ -1428,10 +1444,12 @@ typedef enum VkPipelineStageFlagBits { VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, + VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000, VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000, VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000, VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000, - VK_PIPELINE_STAGE_RAYTRACING_BIT_NVX = 0x00200000, + VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = 0x00200000, + VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000, VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000, VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000, VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF @@ -1447,6 +1465,10 @@ typedef enum VkImageAspectFlagBits { VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010, VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020, VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040, + VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080, + VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100, + VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200, + VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT, @@ -1521,8 +1543,10 @@ typedef enum VkBufferUsageFlagBits { VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800, + VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000, VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200, - VK_BUFFER_USAGE_RAYTRACING_BIT_NVX = 0x00000400, + VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = 0x00000400, VK_BUFFER_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkBufferUsageFlagBits; typedef VkFlags VkBufferUsageFlags; @@ -1537,7 +1561,7 @@ typedef enum VkPipelineCreateFlagBits { VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004, VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008, VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010, - VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NVX = 0x00000020, + VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020, VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT, VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = VK_PIPELINE_CREATE_DISPATCH_BASE, VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF @@ -1554,12 +1578,12 @@ typedef enum VkShaderStageFlagBits { VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020, VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F, VK_SHADER_STAGE_ALL = 0x7FFFFFFF, - VK_SHADER_STAGE_RAYGEN_BIT_NVX = 0x00000100, - VK_SHADER_STAGE_ANY_HIT_BIT_NVX = 0x00000200, - VK_SHADER_STAGE_CLOSEST_HIT_BIT_NVX = 0x00000400, - VK_SHADER_STAGE_MISS_BIT_NVX = 0x00000800, - VK_SHADER_STAGE_INTERSECTION_BIT_NVX = 0x00001000, - VK_SHADER_STAGE_CALLABLE_BIT_NVX = 0x00002000, + VK_SHADER_STAGE_RAYGEN_BIT_NV = 0x00000100, + VK_SHADER_STAGE_ANY_HIT_BIT_NV = 0x00000200, + VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = 0x00000400, + VK_SHADER_STAGE_MISS_BIT_NV = 0x00000800, + VK_SHADER_STAGE_INTERSECTION_BIT_NV = 0x00001000, + VK_SHADER_STAGE_CALLABLE_BIT_NV = 0x00002000, VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040, VK_SHADER_STAGE_MESH_BIT_NV = 0x00000080, VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF @@ -1643,13 +1667,16 @@ typedef enum VkAccessFlagBits { VK_ACCESS_HOST_WRITE_BIT = 0x00004000, VK_ACCESS_MEMORY_READ_BIT = 0x00008000, VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000, + VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000, + VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000, VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000, VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000, VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000, VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000, VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000, - VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NVX = 0x00200000, - VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NVX = 0x00400000, + VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000, + VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000, VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF } VkAccessFlagBits; typedef VkFlags VkAccessFlags; @@ -6076,9 +6103,10 @@ typedef enum VkDriverIdKHR { VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = 7, VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = 8, VK_DRIVER_ID_ARM_PROPRIETARY_KHR = 9, + VK_DRIVER_ID_GOOGLE_PASTEL_KHR = 10, VK_DRIVER_ID_BEGIN_RANGE_KHR = VK_DRIVER_ID_AMD_PROPRIETARY_KHR, - VK_DRIVER_ID_END_RANGE_KHR = VK_DRIVER_ID_ARM_PROPRIETARY_KHR, - VK_DRIVER_ID_RANGE_SIZE_KHR = (VK_DRIVER_ID_ARM_PROPRIETARY_KHR - VK_DRIVER_ID_AMD_PROPRIETARY_KHR + 1), + VK_DRIVER_ID_END_RANGE_KHR = VK_DRIVER_ID_GOOGLE_PASTEL_KHR, + VK_DRIVER_ID_RANGE_SIZE_KHR = (VK_DRIVER_ID_GOOGLE_PASTEL_KHR - VK_DRIVER_ID_AMD_PROPRIETARY_KHR + 1), VK_DRIVER_ID_MAX_ENUM_KHR = 0x7FFFFFFF } VkDriverIdKHR; @@ -6092,7 +6120,7 @@ typedef struct VkConformanceVersionKHR { typedef struct VkPhysicalDeviceDriverPropertiesKHR { VkStructureType sType; void* pNext; - uint32_t driverID; + VkDriverIdKHR driverID; char driverName[VK_MAX_DRIVER_NAME_SIZE_KHR]; char driverInfo[VK_MAX_DRIVER_INFO_SIZE_KHR]; VkConformanceVersionKHR conformanceVersion; @@ -6157,7 +6185,7 @@ typedef enum VkDebugReportObjectTypeEXT { VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000, - VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NVX_EXT = 1000165000, + VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000, VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT, @@ -6359,6 +6387,95 @@ typedef struct VkDedicatedAllocationMemoryAllocateInfoNV { +#define VK_EXT_transform_feedback 1 +#define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1 +#define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback" + +typedef VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT; + +typedef struct VkPhysicalDeviceTransformFeedbackFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 transformFeedback; + VkBool32 geometryStreams; +} VkPhysicalDeviceTransformFeedbackFeaturesEXT; + +typedef struct VkPhysicalDeviceTransformFeedbackPropertiesEXT { + VkStructureType sType; + void* pNext; + uint32_t maxTransformFeedbackStreams; + uint32_t maxTransformFeedbackBuffers; + VkDeviceSize maxTransformFeedbackBufferSize; + uint32_t maxTransformFeedbackStreamDataSize; + uint32_t maxTransformFeedbackBufferDataSize; + uint32_t maxTransformFeedbackBufferDataStride; + VkBool32 transformFeedbackQueries; + VkBool32 transformFeedbackStreamsLinesTriangles; + VkBool32 transformFeedbackRasterizationStreamSelect; + VkBool32 transformFeedbackDraw; +} VkPhysicalDeviceTransformFeedbackPropertiesEXT; + +typedef struct VkPipelineRasterizationStateStreamCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkPipelineRasterizationStateStreamCreateFlagsEXT flags; + uint32_t rasterizationStream; +} VkPipelineRasterizationStateStreamCreateInfoEXT; + + +typedef void (VKAPI_PTR *PFN_vkCmdBindTransformFeedbackBuffersEXT)(VkCommandBuffer commandBuffer, uint32_t firstBinding, uint32_t bindingCount, const VkBuffer* pBuffers, const VkDeviceSize* pOffsets, const VkDeviceSize* pSizes); +typedef void (VKAPI_PTR *PFN_vkCmdBeginTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdEndTransformFeedbackEXT)(VkCommandBuffer commandBuffer, uint32_t firstCounterBuffer, uint32_t counterBufferCount, const VkBuffer* pCounterBuffers, const VkDeviceSize* pCounterBufferOffsets); +typedef void (VKAPI_PTR *PFN_vkCmdBeginQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags, uint32_t index); +typedef void (VKAPI_PTR *PFN_vkCmdEndQueryIndexedEXT)(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t query, uint32_t index); +typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectByteCountEXT)(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR void VKAPI_CALL vkCmdBindTransformFeedbackBuffersEXT( + VkCommandBuffer commandBuffer, + uint32_t firstBinding, + uint32_t bindingCount, + const VkBuffer* pBuffers, + const VkDeviceSize* pOffsets, + const VkDeviceSize* pSizes); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginTransformFeedbackEXT( + VkCommandBuffer commandBuffer, + uint32_t firstCounterBuffer, + uint32_t counterBufferCount, + const VkBuffer* pCounterBuffers, + const VkDeviceSize* pCounterBufferOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndTransformFeedbackEXT( + VkCommandBuffer commandBuffer, + uint32_t firstCounterBuffer, + uint32_t counterBufferCount, + const VkBuffer* pCounterBuffers, + const VkDeviceSize* pCounterBufferOffsets); + +VKAPI_ATTR void VKAPI_CALL vkCmdBeginQueryIndexedEXT( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + VkQueryControlFlags flags, + uint32_t index); + +VKAPI_ATTR void VKAPI_CALL vkCmdEndQueryIndexedEXT( + VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + uint32_t index); + +VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectByteCountEXT( + VkCommandBuffer commandBuffer, + uint32_t instanceCount, + uint32_t firstInstance, + VkBuffer counterBuffer, + VkDeviceSize counterBufferOffset, + uint32_t counterOffset, + uint32_t vertexStride); +#endif + #define VK_AMD_draw_indirect_count 1 #define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1 #define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count" @@ -7341,7 +7458,7 @@ typedef struct VkDebugUtilsMessengerCallbackDataEXT { typedef VkBool32 (VKAPI_PTR *PFN_vkDebugUtilsMessengerCallbackEXT)( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData); @@ -7676,6 +7793,63 @@ typedef struct VkPipelineCoverageModulationStateCreateInfoNV { #define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage" +#define VK_EXT_image_drm_format_modifier 1 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1 +#define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier" + +typedef struct VkDrmFormatModifierPropertiesEXT { + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + VkFormatFeatureFlags drmFormatModifierTilingFeatures; +} VkDrmFormatModifierPropertiesEXT; + +typedef struct VkDrmFormatModifierPropertiesListEXT { + VkStructureType sType; + void* pNext; + uint32_t drmFormatModifierCount; + VkDrmFormatModifierPropertiesEXT* pDrmFormatModifierProperties; +} VkDrmFormatModifierPropertiesListEXT; + +typedef struct VkPhysicalDeviceImageDrmFormatModifierInfoEXT { + VkStructureType sType; + const void* pNext; + uint64_t drmFormatModifier; + VkSharingMode sharingMode; + uint32_t queueFamilyIndexCount; + const uint32_t* pQueueFamilyIndices; +} VkPhysicalDeviceImageDrmFormatModifierInfoEXT; + +typedef struct VkImageDrmFormatModifierListCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint32_t drmFormatModifierCount; + const uint64_t* pDrmFormatModifiers; +} VkImageDrmFormatModifierListCreateInfoEXT; + +typedef struct VkImageDrmFormatModifierExplicitCreateInfoEXT { + VkStructureType sType; + const void* pNext; + uint64_t drmFormatModifier; + uint32_t drmFormatModifierPlaneCount; + const VkSubresourceLayout* pPlaneLayouts; +} VkImageDrmFormatModifierExplicitCreateInfoEXT; + +typedef struct VkImageDrmFormatModifierPropertiesEXT { + VkStructureType sType; + void* pNext; + uint64_t drmFormatModifier; +} VkImageDrmFormatModifierPropertiesEXT; + + +typedef VkResult (VKAPI_PTR *PFN_vkGetImageDrmFormatModifierPropertiesEXT)(VkDevice device, VkImage image, VkImageDrmFormatModifierPropertiesEXT* pProperties); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetImageDrmFormatModifierPropertiesEXT( + VkDevice device, + VkImage image, + VkImageDrmFormatModifierPropertiesEXT* pProperties); +#endif + #define VK_EXT_validation_cache 1 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkValidationCacheEXT) @@ -7940,81 +8114,113 @@ VKAPI_ATTR void VKAPI_CALL vkCmdSetCoarseSampleOrderNV( const VkCoarseSampleOrderCustomNV* pCustomSampleOrders); #endif -#define VK_NVX_raytracing 1 -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNVX) - -#define VK_NVX_RAYTRACING_SPEC_VERSION 1 -#define VK_NVX_RAYTRACING_EXTENSION_NAME "VK_NVX_raytracing" - - -typedef enum VkGeometryTypeNVX { - VK_GEOMETRY_TYPE_TRIANGLES_NVX = 0, - VK_GEOMETRY_TYPE_AABBS_NVX = 1, - VK_GEOMETRY_TYPE_BEGIN_RANGE_NVX = VK_GEOMETRY_TYPE_TRIANGLES_NVX, - VK_GEOMETRY_TYPE_END_RANGE_NVX = VK_GEOMETRY_TYPE_AABBS_NVX, - VK_GEOMETRY_TYPE_RANGE_SIZE_NVX = (VK_GEOMETRY_TYPE_AABBS_NVX - VK_GEOMETRY_TYPE_TRIANGLES_NVX + 1), - VK_GEOMETRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF -} VkGeometryTypeNVX; - -typedef enum VkAccelerationStructureTypeNVX { - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX = 0, - VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX = 1, - VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NVX = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX, - VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NVX = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX, - VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NVX = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NVX - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NVX + 1), - VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF -} VkAccelerationStructureTypeNVX; - -typedef enum VkCopyAccelerationStructureModeNVX { - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX = 0, - VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX = 1, - VK_COPY_ACCELERATION_STRUCTURE_MODE_BEGIN_RANGE_NVX = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX, - VK_COPY_ACCELERATION_STRUCTURE_MODE_END_RANGE_NVX = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX, - VK_COPY_ACCELERATION_STRUCTURE_MODE_RANGE_SIZE_NVX = (VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NVX - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NVX + 1), - VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_NVX = 0x7FFFFFFF -} VkCopyAccelerationStructureModeNVX; - - -typedef enum VkGeometryFlagBitsNVX { - VK_GEOMETRY_OPAQUE_BIT_NVX = 0x00000001, - VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NVX = 0x00000002, - VK_GEOMETRY_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF -} VkGeometryFlagBitsNVX; -typedef VkFlags VkGeometryFlagsNVX; - -typedef enum VkGeometryInstanceFlagBitsNVX { - VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NVX = 0x00000001, - VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_FLIP_WINDING_BIT_NVX = 0x00000002, - VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NVX = 0x00000004, - VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NVX = 0x00000008, - VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF -} VkGeometryInstanceFlagBitsNVX; -typedef VkFlags VkGeometryInstanceFlagsNVX; - -typedef enum VkBuildAccelerationStructureFlagBitsNVX { - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NVX = 0x00000001, - VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NVX = 0x00000002, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NVX = 0x00000004, - VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NVX = 0x00000008, - VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NVX = 0x00000010, - VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF -} VkBuildAccelerationStructureFlagBitsNVX; -typedef VkFlags VkBuildAccelerationStructureFlagsNVX; - -typedef struct VkRaytracingPipelineCreateInfoNVX { - VkStructureType sType; - const void* pNext; - VkPipelineCreateFlags flags; - uint32_t stageCount; - const VkPipelineShaderStageCreateInfo* pStages; - const uint32_t* pGroupNumbers; - uint32_t maxRecursionDepth; - VkPipelineLayout layout; - VkPipeline basePipelineHandle; - int32_t basePipelineIndex; -} VkRaytracingPipelineCreateInfoNVX; - -typedef struct VkGeometryTrianglesNVX { +#define VK_NV_ray_tracing 1 +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureNV) + +#define VK_NV_RAY_TRACING_SPEC_VERSION 2 +#define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing" +#define VK_SHADER_UNUSED_NV (~0U) + + +typedef enum VkRayTracingShaderGroupTypeNV { + VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = 0, + VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = 1, + VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = 2, + VK_RAY_TRACING_SHADER_GROUP_TYPE_BEGIN_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV, + VK_RAY_TRACING_SHADER_GROUP_TYPE_END_RANGE_NV = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV, + VK_RAY_TRACING_SHADER_GROUP_TYPE_RANGE_SIZE_NV = (VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV - VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV + 1), + VK_RAY_TRACING_SHADER_GROUP_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkRayTracingShaderGroupTypeNV; + +typedef enum VkGeometryTypeNV { + VK_GEOMETRY_TYPE_TRIANGLES_NV = 0, + VK_GEOMETRY_TYPE_AABBS_NV = 1, + VK_GEOMETRY_TYPE_BEGIN_RANGE_NV = VK_GEOMETRY_TYPE_TRIANGLES_NV, + VK_GEOMETRY_TYPE_END_RANGE_NV = VK_GEOMETRY_TYPE_AABBS_NV, + VK_GEOMETRY_TYPE_RANGE_SIZE_NV = (VK_GEOMETRY_TYPE_AABBS_NV - VK_GEOMETRY_TYPE_TRIANGLES_NV + 1), + VK_GEOMETRY_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkGeometryTypeNV; + +typedef enum VkAccelerationStructureTypeNV { + VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0, + VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1, + VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV, + VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV, + VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV + 1), + VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureTypeNV; + +typedef enum VkCopyAccelerationStructureModeNV { + VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = 0, + VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = 1, + VK_COPY_ACCELERATION_STRUCTURE_MODE_BEGIN_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV, + VK_COPY_ACCELERATION_STRUCTURE_MODE_END_RANGE_NV = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV, + VK_COPY_ACCELERATION_STRUCTURE_MODE_RANGE_SIZE_NV = (VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV - VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV + 1), + VK_COPY_ACCELERATION_STRUCTURE_MODE_MAX_ENUM_NV = 0x7FFFFFFF +} VkCopyAccelerationStructureModeNV; + +typedef enum VkAccelerationStructureMemoryRequirementsTypeNV { + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV, + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV - VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV + 1), + VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_MAX_ENUM_NV = 0x7FFFFFFF +} VkAccelerationStructureMemoryRequirementsTypeNV; + + +typedef enum VkGeometryFlagBitsNV { + VK_GEOMETRY_OPAQUE_BIT_NV = 0x00000001, + VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = 0x00000002, + VK_GEOMETRY_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkGeometryFlagBitsNV; +typedef VkFlags VkGeometryFlagsNV; + +typedef enum VkGeometryInstanceFlagBitsNV { + VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = 0x00000001, + VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002, + VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = 0x00000004, + VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = 0x00000008, + VK_GEOMETRY_INSTANCE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkGeometryInstanceFlagBitsNV; +typedef VkFlags VkGeometryInstanceFlagsNV; + +typedef enum VkBuildAccelerationStructureFlagBitsNV { + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = 0x00000001, + VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = 0x00000002, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = 0x00000004, + VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = 0x00000008, + VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = 0x00000010, + VK_BUILD_ACCELERATION_STRUCTURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF +} VkBuildAccelerationStructureFlagBitsNV; +typedef VkFlags VkBuildAccelerationStructureFlagsNV; + +typedef struct VkRayTracingShaderGroupCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkRayTracingShaderGroupTypeNV type; + uint32_t generalShader; + uint32_t closestHitShader; + uint32_t anyHitShader; + uint32_t intersectionShader; +} VkRayTracingShaderGroupCreateInfoNV; + +typedef struct VkRayTracingPipelineCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkPipelineCreateFlags flags; + uint32_t stageCount; + const VkPipelineShaderStageCreateInfo* pStages; + uint32_t groupCount; + const VkRayTracingShaderGroupCreateInfoNV* pGroups; + uint32_t maxRecursionDepth; + VkPipelineLayout layout; + VkPipeline basePipelineHandle; + int32_t basePipelineIndex; +} VkRayTracingPipelineCreateInfoNV; + +typedef struct VkGeometryTrianglesNV { VkStructureType sType; const void* pNext; VkBuffer vertexData; @@ -8028,136 +8234,138 @@ typedef struct VkGeometryTrianglesNVX { VkIndexType indexType; VkBuffer transformData; VkDeviceSize transformOffset; -} VkGeometryTrianglesNVX; +} VkGeometryTrianglesNV; -typedef struct VkGeometryAABBNVX { +typedef struct VkGeometryAABBNV { VkStructureType sType; const void* pNext; VkBuffer aabbData; uint32_t numAABBs; uint32_t stride; VkDeviceSize offset; -} VkGeometryAABBNVX; +} VkGeometryAABBNV; -typedef struct VkGeometryDataNVX { - VkGeometryTrianglesNVX triangles; - VkGeometryAABBNVX aabbs; -} VkGeometryDataNVX; +typedef struct VkGeometryDataNV { + VkGeometryTrianglesNV triangles; + VkGeometryAABBNV aabbs; +} VkGeometryDataNV; -typedef struct VkGeometryNVX { - VkStructureType sType; - const void* pNext; - VkGeometryTypeNVX geometryType; - VkGeometryDataNVX geometry; - VkGeometryFlagsNVX flags; -} VkGeometryNVX; - -typedef struct VkAccelerationStructureCreateInfoNVX { - VkStructureType sType; - const void* pNext; - VkAccelerationStructureTypeNVX type; - VkBuildAccelerationStructureFlagsNVX flags; - VkDeviceSize compactedSize; - uint32_t instanceCount; - uint32_t geometryCount; - const VkGeometryNVX* pGeometries; -} VkAccelerationStructureCreateInfoNVX; - -typedef struct VkBindAccelerationStructureMemoryInfoNVX { - VkStructureType sType; - const void* pNext; - VkAccelerationStructureNVX accelerationStructure; - VkDeviceMemory memory; - VkDeviceSize memoryOffset; - uint32_t deviceIndexCount; - const uint32_t* pDeviceIndices; -} VkBindAccelerationStructureMemoryInfoNVX; - -typedef struct VkDescriptorAccelerationStructureInfoNVX { - VkStructureType sType; - const void* pNext; - uint32_t accelerationStructureCount; - const VkAccelerationStructureNVX* pAccelerationStructures; -} VkDescriptorAccelerationStructureInfoNVX; +typedef struct VkGeometryNV { + VkStructureType sType; + const void* pNext; + VkGeometryTypeNV geometryType; + VkGeometryDataNV geometry; + VkGeometryFlagsNV flags; +} VkGeometryNV; -typedef struct VkAccelerationStructureMemoryRequirementsInfoNVX { - VkStructureType sType; - const void* pNext; - VkAccelerationStructureNVX accelerationStructure; -} VkAccelerationStructureMemoryRequirementsInfoNVX; +typedef struct VkAccelerationStructureInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureTypeNV type; + VkBuildAccelerationStructureFlagsNV flags; + uint32_t instanceCount; + uint32_t geometryCount; + const VkGeometryNV* pGeometries; +} VkAccelerationStructureInfoNV; + +typedef struct VkAccelerationStructureCreateInfoNV { + VkStructureType sType; + const void* pNext; + VkDeviceSize compactedSize; + VkAccelerationStructureInfoNV info; +} VkAccelerationStructureCreateInfoNV; -typedef struct VkPhysicalDeviceRaytracingPropertiesNVX { +typedef struct VkBindAccelerationStructureMemoryInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureNV accelerationStructure; + VkDeviceMemory memory; + VkDeviceSize memoryOffset; + uint32_t deviceIndexCount; + const uint32_t* pDeviceIndices; +} VkBindAccelerationStructureMemoryInfoNV; + +typedef struct VkWriteDescriptorSetAccelerationStructureNV { + VkStructureType sType; + const void* pNext; + uint32_t accelerationStructureCount; + const VkAccelerationStructureNV* pAccelerationStructures; +} VkWriteDescriptorSetAccelerationStructureNV; + +typedef struct VkAccelerationStructureMemoryRequirementsInfoNV { + VkStructureType sType; + const void* pNext; + VkAccelerationStructureMemoryRequirementsTypeNV type; + VkAccelerationStructureNV accelerationStructure; +} VkAccelerationStructureMemoryRequirementsInfoNV; + +typedef struct VkPhysicalDeviceRayTracingPropertiesNV { VkStructureType sType; void* pNext; - uint32_t shaderHeaderSize; + uint32_t shaderGroupHandleSize; uint32_t maxRecursionDepth; - uint32_t maxGeometryCount; -} VkPhysicalDeviceRaytracingPropertiesNVX; - - -typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNVX)(VkDevice device, const VkAccelerationStructureCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNVX* pAccelerationStructure); -typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNVX)(VkDevice device, VkAccelerationStructureNVX accelerationStructure, const VkAllocationCallbacks* pAllocator); -typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements); -typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureScratchMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements); -typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNVX)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos); -typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureTypeNVX type, uint32_t instanceCount, VkBuffer instanceData, VkDeviceSize instanceOffset, uint32_t geometryCount, const VkGeometryNVX* pGeometries, VkBuildAccelerationStructureFlagsNVX flags, VkBool32 update, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkBuffer scratch, VkDeviceSize scratchOffset); -typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkCopyAccelerationStructureModeNVX mode); -typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNVX)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, uint32_t width, uint32_t height); -typedef VkResult (VKAPI_PTR *PFN_vkCreateRaytracingPipelinesNVX)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRaytracingPipelineCreateInfoNVX* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); -typedef VkResult (VKAPI_PTR *PFN_vkGetRaytracingShaderHandlesNVX)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); -typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNVX)(VkDevice device, VkAccelerationStructureNVX accelerationStructure, size_t dataSize, void* pData); -typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructurePropertiesNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX accelerationStructure, VkQueryType queryType, VkQueryPool queryPool, uint32_t query); -typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNVX)(VkDevice device, VkPipeline pipeline, uint32_t shader); + uint32_t maxShaderGroupStride; + uint32_t shaderGroupBaseAlignment; + uint64_t maxGeometryCount; + uint64_t maxInstanceCount; + uint64_t maxTriangleCount; + uint32_t maxDescriptorSetAccelerationStructures; +} VkPhysicalDeviceRayTracingPropertiesNV; + + +typedef VkResult (VKAPI_PTR *PFN_vkCreateAccelerationStructureNV)(VkDevice device, const VkAccelerationStructureCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkAccelerationStructureNV* pAccelerationStructure); +typedef void (VKAPI_PTR *PFN_vkDestroyAccelerationStructureNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks* pAllocator); +typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNV)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements); +typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNV)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); +typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNV)(VkCommandBuffer commandBuffer, const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, VkBool32 update, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset); +typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNV)(VkCommandBuffer commandBuffer, VkAccelerationStructureNV dst, VkAccelerationStructureNV src, VkCopyAccelerationStructureModeNV mode); +typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNV)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth); +typedef VkResult (VKAPI_PTR *PFN_vkCreateRayTracingPipelinesNV)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); +typedef VkResult (VKAPI_PTR *PFN_vkGetRayTracingShaderGroupHandlesNV)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData); +typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNV)(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void* pData); +typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructuresPropertiesNV)(VkCommandBuffer commandBuffer, uint32_t accelerationStructureCount, const VkAccelerationStructureNV* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, uint32_t firstQuery); +typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNV)(VkDevice device, VkPipeline pipeline, uint32_t shader); #ifndef VK_NO_PROTOTYPES -VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNVX( +VKAPI_ATTR VkResult VKAPI_CALL vkCreateAccelerationStructureNV( VkDevice device, - const VkAccelerationStructureCreateInfoNVX* pCreateInfo, + const VkAccelerationStructureCreateInfoNV* pCreateInfo, const VkAllocationCallbacks* pAllocator, - VkAccelerationStructureNVX* pAccelerationStructure); + VkAccelerationStructureNV* pAccelerationStructure); -VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNVX( +VKAPI_ATTR void VKAPI_CALL vkDestroyAccelerationStructureNV( VkDevice device, - VkAccelerationStructureNVX accelerationStructure, + VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks* pAllocator); -VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNVX( +VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureMemoryRequirementsNV( VkDevice device, - const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, + const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements); -VKAPI_ATTR void VKAPI_CALL vkGetAccelerationStructureScratchMemoryRequirementsNVX( - VkDevice device, - const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, - VkMemoryRequirements2KHR* pMemoryRequirements); - -VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNVX( +VKAPI_ATTR VkResult VKAPI_CALL vkBindAccelerationStructureMemoryNV( VkDevice device, uint32_t bindInfoCount, - const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos); + const VkBindAccelerationStructureMemoryInfoNV* pBindInfos); -VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNVX( +VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNV( VkCommandBuffer commandBuffer, - VkAccelerationStructureTypeNVX type, - uint32_t instanceCount, + const VkAccelerationStructureInfoNV* pInfo, VkBuffer instanceData, VkDeviceSize instanceOffset, - uint32_t geometryCount, - const VkGeometryNVX* pGeometries, - VkBuildAccelerationStructureFlagsNVX flags, VkBool32 update, - VkAccelerationStructureNVX dst, - VkAccelerationStructureNVX src, + VkAccelerationStructureNV dst, + VkAccelerationStructureNV src, VkBuffer scratch, VkDeviceSize scratchOffset); -VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNVX( +VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNV( VkCommandBuffer commandBuffer, - VkAccelerationStructureNVX dst, - VkAccelerationStructureNVX src, - VkCopyAccelerationStructureModeNVX mode); + VkAccelerationStructureNV dst, + VkAccelerationStructureNV src, + VkCopyAccelerationStructureModeNV mode); -VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNVX( +VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNV( VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, @@ -8167,18 +8375,22 @@ VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNVX( VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, + VkBuffer callableShaderBindingTableBuffer, + VkDeviceSize callableShaderBindingOffset, + VkDeviceSize callableShaderBindingStride, uint32_t width, - uint32_t height); + uint32_t height, + uint32_t depth); -VKAPI_ATTR VkResult VKAPI_CALL vkCreateRaytracingPipelinesNVX( +VKAPI_ATTR VkResult VKAPI_CALL vkCreateRayTracingPipelinesNV( VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, - const VkRaytracingPipelineCreateInfoNVX* pCreateInfos, + const VkRayTracingPipelineCreateInfoNV* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines); -VKAPI_ATTR VkResult VKAPI_CALL vkGetRaytracingShaderHandlesNVX( +VKAPI_ATTR VkResult VKAPI_CALL vkGetRayTracingShaderGroupHandlesNV( VkDevice device, VkPipeline pipeline, uint32_t firstGroup, @@ -8186,20 +8398,21 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetRaytracingShaderHandlesNVX( size_t dataSize, void* pData); -VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNVX( +VKAPI_ATTR VkResult VKAPI_CALL vkGetAccelerationStructureHandleNV( VkDevice device, - VkAccelerationStructureNVX accelerationStructure, + VkAccelerationStructureNV accelerationStructure, size_t dataSize, void* pData); -VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructurePropertiesNVX( +VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructuresPropertiesNV( VkCommandBuffer commandBuffer, - VkAccelerationStructureNVX accelerationStructure, + uint32_t accelerationStructureCount, + const VkAccelerationStructureNV* pAccelerationStructures, VkQueryType queryType, VkQueryPool queryPool, - uint32_t query); + uint32_t firstQuery); -VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNVX( +VKAPI_ATTR VkResult VKAPI_CALL vkCompileDeferredNV( VkDevice device, VkPipeline pipeline, uint32_t shader); @@ -8296,6 +8509,46 @@ VKAPI_ATTR void VKAPI_CALL vkCmdWriteBufferMarkerAMD( uint32_t marker); #endif +#define VK_EXT_calibrated_timestamps 1 +#define VK_EXT_CALIBRATED_TIMESTAMPS_SPEC_VERSION 1 +#define VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME "VK_EXT_calibrated_timestamps" + + +typedef enum VkTimeDomainEXT { + VK_TIME_DOMAIN_DEVICE_EXT = 0, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1, + VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2, + VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3, + VK_TIME_DOMAIN_BEGIN_RANGE_EXT = VK_TIME_DOMAIN_DEVICE_EXT, + VK_TIME_DOMAIN_END_RANGE_EXT = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT, + VK_TIME_DOMAIN_RANGE_SIZE_EXT = (VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT - VK_TIME_DOMAIN_DEVICE_EXT + 1), + VK_TIME_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF +} VkTimeDomainEXT; + +typedef struct VkCalibratedTimestampInfoEXT { + VkStructureType sType; + const void* pNext; + VkTimeDomainEXT timeDomain; +} VkCalibratedTimestampInfoEXT; + + +typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT)(VkPhysicalDevice physicalDevice, uint32_t* pTimeDomainCount, VkTimeDomainEXT* pTimeDomains); +typedef VkResult (VKAPI_PTR *PFN_vkGetCalibratedTimestampsEXT)(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT* pTimestampInfos, uint64_t* pTimestamps, uint64_t* pMaxDeviation); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceCalibrateableTimeDomainsEXT( + VkPhysicalDevice physicalDevice, + uint32_t* pTimeDomainCount, + VkTimeDomainEXT* pTimeDomains); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetCalibratedTimestampsEXT( + VkDevice device, + uint32_t timestampCount, + const VkCalibratedTimestampInfoEXT* pTimestampInfos, + uint64_t* pTimestamps, + uint64_t* pMaxDeviation); +#endif + #define VK_AMD_shader_core_properties 1 #define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1 #define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties" @@ -8321,6 +8574,29 @@ typedef struct VkPhysicalDeviceShaderCorePropertiesAMD { +#define VK_AMD_memory_overallocation_behavior 1 +#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1 +#define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior" + + +typedef enum VkMemoryOverallocationBehaviorAMD { + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_BEGIN_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_END_RANGE_AMD = VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD, + VK_MEMORY_OVERALLOCATION_BEHAVIOR_RANGE_SIZE_AMD = (VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD - VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD + 1), + VK_MEMORY_OVERALLOCATION_BEHAVIOR_MAX_ENUM_AMD = 0x7FFFFFFF +} VkMemoryOverallocationBehaviorAMD; + +typedef struct VkDeviceMemoryOverallocationCreateInfoAMD { + VkStructureType sType; + const void* pNext; + VkMemoryOverallocationBehaviorAMD overallocationBehavior; +} VkDeviceMemoryOverallocationCreateInfoAMD; + + + #define VK_EXT_vertex_attribute_divisor 1 #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3 #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor" @@ -8516,6 +8792,55 @@ VKAPI_ATTR void VKAPI_CALL vkGetQueueCheckpointDataNV( VkCheckpointDataNV* pCheckpointData); #endif +#define VK_EXT_pci_bus_info 1 +#define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 1 +#define VK_EXT_PCI_BUS_INFO_EXTENSION_NAME "VK_EXT_pci_bus_info" + +typedef struct VkPhysicalDevicePCIBusInfoPropertiesEXT { + VkStructureType sType; + void* pNext; + uint16_t pciDomain; + uint8_t pciBus; + uint8_t pciDevice; + uint8_t pciFunction; +} VkPhysicalDevicePCIBusInfoPropertiesEXT; + + + +#define VK_EXT_scalar_block_layout 1 +#define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1 +#define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout" + +typedef struct VkPhysicalDeviceScalarBlockLayoutFeaturesEXT { + VkStructureType sType; + void* pNext; + VkBool32 scalarBlockLayout; +} VkPhysicalDeviceScalarBlockLayoutFeaturesEXT; + + + +#define VK_GOOGLE_hlsl_functionality1 1 +#define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 0 +#define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1" + + +#define VK_GOOGLE_decorate_string 1 +#define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 0 +#define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string" + + +#define VK_EXT_separate_stencil_usage 1 +#define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1 +#define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage" + +typedef struct VkImageStencilUsageCreateInfoEXT { + VkStructureType sType; + const void* pNext; + VkImageUsageFlags stencilUsage; +} VkImageStencilUsageCreateInfoEXT; + + + #ifdef __cplusplus } #endif diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp index 629ebb1a18..df86af0c3b 100644 --- a/vulkan/libvulkan/api_gen.cpp +++ b/vulkan/libvulkan/api_gen.cpp @@ -556,6 +556,7 @@ VKAPI_ATTR PFN_vkVoidFunction GetDeviceProcAddr(VkDevice device, const char* pNa "vkGetDisplayModeProperties2KHR", "vkGetDisplayPlaneCapabilities2KHR", "vkGetInstanceProcAddr", + "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT", "vkGetPhysicalDeviceDisplayPlaneProperties2KHR", "vkGetPhysicalDeviceDisplayProperties2KHR", "vkGetPhysicalDeviceExternalBufferProperties", diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl index 1f4df1e59d..f04eb03eac 100644 --- a/vulkan/libvulkan/code-generator.tmpl +++ b/vulkan/libvulkan/code-generator.tmpl @@ -1149,6 +1149,7 @@ VK_ANDROID_external_memory_android_hardware_buffer {{else if eq $ext "VK_EXT_direct_mode_display"}}true {{else if eq $ext "VK_EXT_display_surface_counter"}}true {{else if eq $ext "VK_EXT_display_control"}}true + {{else if eq $ext "VK_FUCHSIA_imagepipe_surface"}}true {{else if eq $ext "VK_MVK_ios_surface"}}true {{else if eq $ext "VK_MVK_macos_surface"}}true {{else if eq $ext "VK_NN_vi_surface"}}true diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc index efe622d782..3da4336069 100644 --- a/vulkan/vkjson/vkjson.cc +++ b/vulkan/vkjson/vkjson.cc @@ -325,6 +325,13 @@ struct EnumTraits<VkExternalSemaphoreHandleTypeFlagBits> { } }; +template <> +struct EnumTraits<VkDriverIdKHR> { + static uint32_t min() { return VK_DRIVER_ID_BEGIN_RANGE_KHR; } + static uint32_t max() { return VK_DRIVER_ID_END_RANGE_KHR; } + static bool exist(uint32_t e) { return e >= min() && e <= max(); } +}; + // VkSparseImageFormatProperties template <typename Visitor> @@ -544,6 +551,31 @@ inline bool Iterate(Visitor* visitor, VkPhysicalDeviceFeatures* features) { template <typename Visitor> inline bool Iterate(Visitor* visitor, + VkJsonExtDriverProperties* properties) { + return visitor->Visit("driverPropertiesKHR", + &properties->driver_properties_khr); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkPhysicalDeviceDriverPropertiesKHR* properties) { + return visitor->Visit("driverID", &properties->driverID) && + visitor->Visit("driverName", &properties->driverName) && + visitor->Visit("driverInfo", &properties->driverInfo) && + visitor->Visit("conformanceVersion", &properties->conformanceVersion); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, + VkConformanceVersionKHR* version) { + return visitor->Visit("major", &version->major) && + visitor->Visit("minor", &version->minor) && + visitor->Visit("subminor", &version->subminor) && + visitor->Visit("patch", &version->patch); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonExtVariablePointerFeatures* features) { return visitor->Visit("variablePointerFeaturesKHR", &features->variable_pointer_features_khr); @@ -770,13 +802,19 @@ inline bool Iterate(Visitor* visitor, VkJsonDevice* device) { case VK_API_VERSION_1_0: ret &= visitor->Visit("properties", &device->properties) && visitor->Visit("features", &device->features) && - visitor->Visit("VK_KHR_variable_pointers", - &device->ext_variable_pointer_features) && visitor->Visit("memory", &device->memory) && visitor->Visit("queues", &device->queues) && visitor->Visit("extensions", &device->extensions) && visitor->Visit("layers", &device->layers) && visitor->Visit("formats", &device->formats); + if (device->ext_driver_properties.reported) { + ret &= visitor->Visit("VK_KHR_driver_properties", + &device->ext_driver_properties); + } + if (device->ext_variable_pointer_features.reported) { + ret &= visitor->Visit("VK_KHR_variable_pointers", + &device->ext_variable_pointer_features); + } } return ret; } diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h index 4f97c3ec88..450fb24862 100644 --- a/vulkan/vkjson/vkjson.h +++ b/vulkan/vkjson/vkjson.h @@ -52,11 +52,23 @@ struct VkJsonLayer { std::vector<VkExtensionProperties> extensions; }; +struct VkJsonExtDriverProperties { + VkJsonExtDriverProperties() { + reported = false; + memset(&driver_properties_khr, 0, + sizeof(VkPhysicalDeviceDriverPropertiesKHR)); + } + bool reported; + VkPhysicalDeviceDriverPropertiesKHR driver_properties_khr; +}; + struct VkJsonExtVariablePointerFeatures { VkJsonExtVariablePointerFeatures() { + reported = false; memset(&variable_pointer_features_khr, 0, sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR)); } + bool reported; VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features_khr; }; @@ -87,6 +99,7 @@ struct VkJsonDevice { } VkPhysicalDeviceProperties properties; VkPhysicalDeviceFeatures features; + VkJsonExtDriverProperties ext_driver_properties; VkJsonExtVariablePointerFeatures ext_variable_pointer_features; VkPhysicalDeviceMemoryProperties memory; std::vector<VkQueueFamilyProperties> queues; diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc index 4ec442a4ef..05d4dfea6c 100644 --- a/vulkan/vkjson/vkjson_instance.cc +++ b/vulkan/vkjson/vkjson_instance.cc @@ -71,11 +71,16 @@ VkJsonDevice VkJsonGetDevice(VkInstance instance, const char* const* instance_extensions) { VkJsonDevice device; + PFN_vkGetPhysicalDeviceProperties2KHR vkpGetPhysicalDeviceProperties2KHR = + nullptr; PFN_vkGetPhysicalDeviceFeatures2KHR vkpGetPhysicalDeviceFeatures2KHR = nullptr; if (instance != VK_NULL_HANDLE && HasExtension("VK_KHR_get_physical_device_properties2", instance_extension_count, instance_extensions)) { + vkpGetPhysicalDeviceProperties2KHR = + reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>( + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR")); vkpGetPhysicalDeviceFeatures2KHR = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>( vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR")); @@ -98,15 +103,32 @@ VkJsonDevice VkJsonGetDevice(VkInstance instance, device.layers.data()); } - vkGetPhysicalDeviceProperties(physical_device, &device.properties); if (HasExtension("VK_KHR_get_physical_device_properties2", instance_extension_count, instance_extensions)) { + VkPhysicalDeviceProperties2KHR properties = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, + nullptr, + {} // properties + }; + if (HasExtension("VK_KHR_driver_properties", device.extensions)) { + device.ext_driver_properties.reported = true; + device.ext_driver_properties.driver_properties_khr.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR; + device.ext_driver_properties.driver_properties_khr.pNext = + properties.pNext; + properties.pNext = + &device.ext_driver_properties.driver_properties_khr; + } + vkpGetPhysicalDeviceProperties2KHR(physical_device, &properties); + device.properties = properties.properties; + VkPhysicalDeviceFeatures2KHR features = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR, nullptr, {} // features }; if (HasExtension("VK_KHR_variable_pointers", device.extensions)) { + device.ext_variable_pointer_features.reported = true; device.ext_variable_pointer_features.variable_pointer_features_khr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR; device.ext_variable_pointer_features.variable_pointer_features_khr.pNext = @@ -117,6 +139,7 @@ VkJsonDevice VkJsonGetDevice(VkInstance instance, vkpGetPhysicalDeviceFeatures2KHR(physical_device, &features); device.features = features.features; } else { + vkGetPhysicalDeviceProperties(physical_device, &device.properties); vkGetPhysicalDeviceFeatures(physical_device, &device.features); } vkGetPhysicalDeviceMemoryProperties(physical_device, &device.memory); |