Merge "Simplify process(..) in InputReader_test"
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 1855d26..6a9007c 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -34,23 +34,21 @@
# made today requires touching the same file, just copy the old
# touch step and add it to the end of the list.
#
-# *****************************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
-# *****************************************************************
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
# For example:
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libdvr.so" -print0 | xargs -0 rm -f)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libgui*" -print0 | xargs -0 rm -f)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/thermalserviced)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/thermalservice.rc)
-# ******************************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
-# ******************************************************************
+$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "gpuservice*" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/gpuservice_intermediates)
diff --git a/cmds/bugreportz/Android.bp b/cmds/bugreportz/Android.bp
new file mode 100644
index 0000000..924a3a3
--- /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 10dda56..0000000
--- 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 0000000..d91184a
--- /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 4868555..0000000
--- 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 71658d8..0ee6c3a 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,10 +98,30 @@
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();
}
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 131aff3..58095b3 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -41,8 +41,7 @@
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/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 68a4f21..9e59f58 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -39,10 +39,27 @@
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 1a45436..72d1de9 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1917,7 +1917,7 @@
am_args.push_back("android.intent.extra.SCREENSHOT");
am_args.push_back(ds.screenshot_path_);
}
- if (ds.options_->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.options_->notification_title);
@@ -1940,37 +1940,95 @@
}
}
-// 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) {
- options->extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
- if (!options->extra_options.empty()) {
- // Framework uses a system property to override some command-line args.
- // Currently, it contains the type of the requested bugreport.
- if (options->extra_options == "bugreportplus") {
+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;
- } else if (options->extra_options == "bugreportremote") {
+ options->do_broadcast = true;
+ break;
+ case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
options->do_vibrate = false;
options->is_remote_mode = true;
options->do_fb = false;
- } else if (options->extra_options == "bugreportwear") {
+ 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;
- } else if (options->extra_options == "bugreporttelephony") {
+ options->do_fb = true;
+ options->do_broadcast = true;
+ break;
+ case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
options->telephony_only = true;
- } else if (options->extra_options == "bugreportwifi") {
+ 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", options->extra_options.c_str());
+ 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()) {
@@ -1988,6 +2046,40 @@
}
}
+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;
@@ -2052,11 +2144,16 @@
return true;
}
-Dumpstate::RunStatus Dumpstate::RunWithOptions(std::unique_ptr<DumpOptions> options) {
- if (!options->ValidateOptions()) {
+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;
}
- options_ = std::move(options);
/* set as high priority, and protect from OOM killer */
setpriority(PRIO_PROCESS, 0, -20);
@@ -2278,7 +2375,8 @@
std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
Dumpstate::RunStatus status = options->Initialize(argc, argv);
if (status == Dumpstate::RunStatus::OK) {
- status = ds.RunWithOptions(std::move(options));
+ ds.SetOptions(std::move(options));
+ status = ds.Run();
}
switch (status) {
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index c2f7f6a..5e7f71d 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;
@@ -185,6 +189,16 @@
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();
@@ -294,8 +308,11 @@
struct DumpOptions;
- /* Main entry point for running a complete bugreport. Takes ownership of options. */
- RunStatus RunWithOptions(std::unique_ptr<DumpOptions> options);
+ /* Main entry point for running a complete bugreport. */
+ RunStatus Run();
+
+ /* Sets runtime options. */
+ void SetOptions(std::unique_ptr<DumpOptions> options);
// TODO: add other options from DumpState.
/*
@@ -317,6 +334,7 @@
// 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
@@ -328,6 +346,9 @@
/* 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;
};
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 2cb9800..9ca894d 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -159,10 +159,11 @@
};
// clang-format on
- Dumpstate::DumpOptions options;
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);
@@ -170,10 +171,10 @@
EXPECT_FALSE(options_.use_control_socket);
EXPECT_FALSE(options_.show_header_only);
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.do_fb);
+ EXPECT_TRUE(options_.do_fb);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.do_broadcast);
+ EXPECT_TRUE(options_.do_broadcast);
}
TEST_F(DumpOptionsTest, InitializePartial1) {
@@ -202,10 +203,10 @@
// Other options retain default values
EXPECT_FALSE(options_.show_header_only);
EXPECT_TRUE(options_.do_vibrate);
- EXPECT_FALSE(options_.do_fb);
+ EXPECT_TRUE(options_.do_fb);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.do_broadcast);
+ EXPECT_TRUE(options_.do_broadcast);
}
TEST_F(DumpOptionsTest, InitializePartial2) {
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 4ad5c4b..6cbb691 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -82,8 +82,12 @@
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() {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 7a47724..f0c21f5 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -387,23 +387,28 @@
return mStrictModePolicy;
}
-uid_t IPCThreadState::setWorkSource(uid_t uid)
+int64_t IPCThreadState::setCallingWorkSourceUid(uid_t uid)
{
- uid_t returnValue = mWorkSource;
+ // Note: we currently only use half of the int64. We return an int64 for extensibility.
+ int64_t token = mWorkSource;
mWorkSource = uid;
- return returnValue;
+ return token;
}
-uid_t IPCThreadState::getWorkSource() const
+uid_t IPCThreadState::getCallingWorkSourceUid() const
{
return mWorkSource;
}
-uid_t IPCThreadState::clearWorkSource()
+int64_t IPCThreadState::clearCallingWorkSource()
{
- uid_t returnValue = mWorkSource;
- mWorkSource = kUnsetWorkSource;
- return returnValue;
+ return setCallingWorkSourceUid(kUnsetWorkSource);
+}
+
+void IPCThreadState::restoreCallingWorkSource(int64_t token)
+{
+ uid_t uid = (int)token;
+ setCallingWorkSourceUid(uid);
}
void IPCThreadState::setLastTransactionBinderFlags(int32_t flags)
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 532f7f1..643f428 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -601,7 +601,7 @@
{
writeInt32(IPCThreadState::self()->getStrictModePolicy() |
STRICT_MODE_PENALTY_GATHER);
- writeInt32(IPCThreadState::self()->getWorkSource());
+ writeInt32(IPCThreadState::self()->getCallingWorkSourceUid());
// currently the interface identification token is just its name as a string
return writeString16(interface);
}
@@ -631,7 +631,7 @@
}
// WorkSource.
int32_t workSource = readInt32();
- threadState->setWorkSource(workSource);
+ threadState->setCallingWorkSourceUid(workSource);
// Interface descriptor.
const String16 str(readString16());
if (str == interface) {
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 5888e14..de126d5 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -47,12 +47,14 @@
void setStrictModePolicy(int32_t policy);
int32_t getStrictModePolicy() const;
- // See Binder#setThreadWorkSource in Binder.java.
- uid_t setWorkSource(uid_t uid);
- // See Binder#getThreadWorkSource in Binder.java.
- uid_t getWorkSource() const;
- // See Binder#clearThreadWorkSource in Binder.java.
- uid_t clearWorkSource();
+ // See Binder#setCallingWorkSourceUid in Binder.java.
+ int64_t setCallingWorkSourceUid(uid_t uid);
+ // See Binder#getCallingWorkSourceUid in Binder.java.
+ uid_t getCallingWorkSourceUid() const;
+ // See Binder#clearCallingWorkSource in Binder.java.
+ int64_t clearCallingWorkSource();
+ // See Binder#restoreCallingWorkSource in Binder.java.
+ void restoreCallingWorkSource(int64_t token);
void setLastTransactionBinderFlags(int32_t flags);
int32_t getLastTransactionBinderFlags() const;
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index d16502f..14ce4cb 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -39,6 +39,8 @@
"libutils",
],
+ cpp_std: "c++17",
+
version_script: "libbinder_ndk.map.txt",
}
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 5c26039..e2c0cfa 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -198,6 +198,11 @@
* See AStatus_isOk.
*/
bool isOk() { return get() != nullptr && AStatus_isOk(get()); }
+
+ /**
+ * Convenience method for okay status.
+ */
+ static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); }
};
/**
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 4ee1b67..3594349 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -55,9 +55,9 @@
/**
* 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. 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.
+ * 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.
*
@@ -65,31 +65,35 @@
*
* \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 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 char* (*AParcel_stringAllocator)(void* stringData, size_t length);
+typedef bool (*AParcel_stringAllocator)(void* stringData, int32_t length, char** buffer);
/**
- * This is called to allocate an array of size 'length'.
+ * 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
+ * \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, size_t length);
+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. 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.
+ * 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
*
@@ -97,10 +101,13 @@
* \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 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 char* (*AParcel_stringArrayElementAllocator)(void* arrayData, size_t index, size_t length);
+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.
@@ -110,10 +117,11 @@
* \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.
+ * 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.
+ * 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);
@@ -124,109 +132,127 @@
*
* 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.
+ * 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 a buffer of int32_t of size 'length'.
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef int32_t* (*AParcel_int32ArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_int32ArrayAllocator)(void* arrayData, int32_t length, int32_t** outBuffer);
/**
* This is called to get the underlying data from an arrayData object.
*
* 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.
+ * 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 a buffer of uint32_t of size 'length'.
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef uint32_t* (*AParcel_uint32ArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_uint32ArrayAllocator)(void* arrayData, int32_t length, uint32_t** outBuffer);
/**
* This is called to get the underlying data from an arrayData object.
*
* 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.
+ * 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 a buffer of int64_t of size 'length'.
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef int64_t* (*AParcel_int64ArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_int64ArrayAllocator)(void* arrayData, int32_t length, int64_t** outBuffer);
/**
* This is called to get the underlying data from an arrayData object.
*
* 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.
+ * 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 a buffer of uint64_t of size 'length'.
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef uint64_t* (*AParcel_uint64ArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_uint64ArrayAllocator)(void* arrayData, int32_t length, uint64_t** outBuffer);
/**
* This is called to get the underlying data from an arrayData object.
*
* 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.
+ * 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 a buffer of float of size 'length'.
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef float* (*AParcel_floatArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_floatArrayAllocator)(void* arrayData, int32_t length, float** outBuffer);
/**
* This is called to get the underlying data from an arrayData object.
*
* 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.
+ * 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 a buffer of double of size 'length'.
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef double* (*AParcel_doubleArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_doubleArrayAllocator)(void* arrayData, int32_t length, double** outBuffer);
/**
* This allocates an array of size 'length' inside of arrayData and returns whether or not there was
- * a success.
+ * a success. If length is -1, then this should allocate some representation of a null array.
*
* See also AParcel_readBoolArray
*
* \param arrayData some external representation of an array of bool.
- * \param length the length to allocate arrayData to.
+ * \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, size_t length);
+typedef bool (*AParcel_boolArrayAllocator)(void* arrayData, int32_t length);
/**
* This is called to get the underlying data from an arrayData object at index.
@@ -256,32 +282,38 @@
*
* 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.
+ * 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 a buffer of char16_t of size 'length'.
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef char16_t* (*AParcel_charArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_charArrayAllocator)(void* arrayData, int32_t length, char16_t** outBuffer);
/**
* This is called to get the underlying data from an arrayData object.
*
* 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.
+ * 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 a buffer of int8_t of size 'length'.
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef int8_t* (*AParcel_byteArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_byteArrayAllocator)(void* arrayData, int32_t length, int8_t** outBuffer);
// @END-PRIMITIVE-VECTOR-GETTERS
@@ -297,12 +329,11 @@
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 will not be null on
- * success.
+ * \param binder the out parameter for what is read from the parcel. This may be null.
*
* \return STATUS_OK on successful write.
*/
@@ -310,26 +341,13 @@
__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.
- *
- * \param parcel the parcel to read from.
- * \param binder the out parameter for what is read from the parcel. This may be null even on
- * success.
- *
- * \return STATUS_OK on successful write.
- */
-binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder)
- __INTRODUCED_IN(29);
-
-/**
* 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.
+ * \param fd the value to write to the parcel (-1 to represent a null ParcelFileDescriptor).
*
* \return STATUS_OK on successful write.
*/
@@ -343,7 +361,8 @@
* This corresponds to the SDK's android.os.ParcelFileDescriptor.
*
* \param parcel the parcel to read from.
- * \param binder the out parameter for what is read from the parcel.
+ * \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.
*/
@@ -381,13 +400,15 @@
/**
* 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);
/**
@@ -395,7 +416,8 @@
*
* 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.
+ * the output buffer from this read. If there is a 'null' string on the binder buffer, the allocator
+ * will be called with length -1.
*
* \param parcel the parcel to read from.
* \param stringData some external representation of a string.
@@ -411,7 +433,8 @@
*
* 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.
+ * 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.
@@ -421,7 +444,7 @@
*
* \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, size_t length,
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length,
AParcel_stringArrayElementGetter getter)
__INTRODUCED_IN(29);
@@ -432,7 +455,8 @@
* 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.
+ * 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.
@@ -633,72 +657,72 @@
* 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'.
- * \param length the length of arrayData.
+ * \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* arrayData, 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'.
- * \param length the length of arrayData.
+ * \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* arrayData, 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'.
- * \param length the length of arrayData.
+ * \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* arrayData, 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'.
- * \param length the length of arrayData.
+ * \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* arrayData, 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'.
- * \param length the length of arrayData.
+ * \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* arrayData, 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'.
- * \param length the length of arrayData.
+ * \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* arrayData, size_t length)
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, int32_t length)
__INTRODUCED_IN(29);
/**
@@ -709,36 +733,36 @@
*
* \param parcel the parcel to write to.
* \param arrayData some external representation of an array.
- * \param length the length of arrayData.
+ * \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, size_t length,
+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'.
- * \param length the length of arrayData.
+ * \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* arrayData, 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'.
- * \param length the length of arrayData.
+ * \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* arrayData, size_t length)
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, int32_t length)
__INTRODUCED_IN(29);
/**
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 2ccbe5a..f99c3a9 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -26,8 +26,10 @@
#pragma once
+#include <android/binder_auto_utils.h>
#include <android/binder_parcel.h>
+#include <optional>
#include <string>
#include <vector>
@@ -37,12 +39,37 @@
* This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
*/
template <typename T>
-static inline T* AParcel_stdVectorAllocator(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->data();
+ *outBuffer = vec->data();
+ return true;
+}
+
+/**
+ * This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
+ */
+template <typename T>
+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;
}
/**
@@ -50,13 +77,16 @@
*
* 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.
+ * 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, size_t length) {
+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);
if (length > vec->max_size()) return false;
@@ -65,6 +95,34 @@
}
/**
+ * 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;
+}
+
+/**
* This retrieves the underlying value in a vector which may not be contiguous at index from a
* corresponding vectorData.
*/
@@ -84,166 +142,156 @@
(*vec)[index] = value;
}
-// @START
/**
- * Writes a vector of int32_t 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.
*/
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) {
- return AParcel_writeInt32Array(parcel, vec.data(), vec.size());
+template <typename T>
+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 of int32_t from the next location in a non-null parcel.
+ * Convenience method to write a nullable strong binder.
*/
-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>);
+static inline binder_status_t AParcel_writeNullableStrongBinder(AParcel* parcel,
+ const SpAIBinder& binder) {
+ return AParcel_writeStrongBinder(parcel, binder.get());
}
/**
- * Writes a vector of uint32_t to the next location in a non-null parcel.
+ * Convenience method to read a nullable strong binder.
*/
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) {
- return AParcel_writeUint32Array(parcel, vec.data(), vec.size());
+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;
}
/**
- * Reads a vector of uint32_t from the next location in a non-null parcel.
+ * Convenience method to write a strong binder but return an error if it is null.
*/
-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_stdVectorAllocator<uint32_t>);
+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());
}
/**
- * Writes a vector of int64_t to the next location in a non-null parcel.
+ * Convenience method to read a strong binder but return an error if it is null.
*/
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) {
- return AParcel_writeInt64Array(parcel, vec.data(), vec.size());
+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;
}
/**
- * Reads a vector of int64_t from the next location in a non-null parcel.
+ * Convenience method to write a ParcelFileDescriptor where -1 represents a null value.
*/
-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>);
+static inline binder_status_t AParcel_writeNullableParcelFileDescriptor(
+ AParcel* parcel, const ScopedFileDescriptor& fd) {
+ return AParcel_writeParcelFileDescriptor(parcel, fd.get());
}
/**
- * Writes a vector of uint64_t to the next location in a non-null parcel.
+ * Convenience method to read a ParcelFileDescriptor where -1 represents a null value.
*/
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) {
- return AParcel_writeUint64Array(parcel, vec.data(), vec.size());
+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;
}
/**
- * Reads a vector of uint64_t from the next location in a non-null parcel.
+ * Convenience method to write a valid ParcelFileDescriptor.
*/
-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>);
+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());
}
/**
- * Writes a vector of float to the next location in a non-null parcel.
+ * Convenience method to read a valid ParcelFileDescriptor.
*/
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) {
- return AParcel_writeFloatArray(parcel, vec.data(), vec.size());
+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;
}
/**
- * Reads a vector of float from the next location in a non-null parcel.
- */
-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>);
-}
-
-/**
- * Writes a vector of double to the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) {
- return AParcel_writeDoubleArray(parcel, vec.data(), vec.size());
-}
-
-/**
- * Reads a vector of double from the next location in a non-null parcel.
- */
-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_stdVectorAllocator<double>);
-}
-
-/**
- * Writes a vector of bool to the next location in a non-null parcel.
- */
-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>);
-}
-
-/**
- * Reads a vector of bool from the next location in a non-null parcel.
- */
-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_stdVectorExternalAllocator<bool>,
- AParcel_stdVectorSetter<bool>);
-}
-
-/**
- * Writes a vector of char16_t to the next location in a non-null parcel.
- */
-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.
- */
-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>);
-}
-
-/**
- * Writes a vector of int8_t to the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int8_t>& vec) {
- return AParcel_writeByteArray(parcel, vec.data(), vec.size());
-}
-
-/**
- * Reads a vector of int8_t from the next location in a non-null parcel.
- */
-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>);
-}
-
-// @END
-
-/**
* 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 char* AParcel_stdStringAllocator(void* stringData, size_t length) {
+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);
- return &(*str)[0];
+ *buffer = &(*str)[0];
+ return true;
}
/**
- * Allocates a std::string inside of a std::vector<std::string> at index index to size 'length'.
+ * 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 char* AParcel_stdVectorStringElementAllocator(void* vectorData, size_t index,
- size_t length) {
- std::vector<std::string>* vec = static_cast<std::vector<std::string>*>(vectorData);
+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);
- element.resize(length - 1);
- return &element[0];
+ return AParcel_stdStringAllocator(static_cast<void*>(&element), length, buffer);
}
/**
@@ -253,7 +301,6 @@
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();
@@ -261,6 +308,40 @@
}
/**
+ * 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) {
@@ -276,6 +357,27 @@
}
/**
+ * 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,
@@ -297,6 +399,334 @@
}
/**
+ * 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.
+ */
+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.
+ */
+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_nullableStdVectorAllocator<int32_t>);
+}
+
+/**
+ * Writes a vector of uint32_t to the next location in a non-null parcel.
+ */
+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.
+ */
+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_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.
+ */
+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.
+ */
+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_nullableStdVectorAllocator<int64_t>);
+}
+
+/**
+ * Writes a vector of uint64_t to the next location in a non-null parcel.
+ */
+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.
+ */
+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_nullableStdVectorAllocator<uint64_t>);
+}
+
+/**
+ * Writes a vector of float to the next location in a non-null parcel.
+ */
+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.
+ */
+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_nullableStdVectorAllocator<float>);
+}
+
+/**
+ * Writes a vector of double to the next location in a non-null parcel.
+ */
+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.
+ */
+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_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.
+ */
+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.
+ */
+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_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.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) {
+ return AParcel_writeCharArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of char16_t to the next location in a non-null parcel.
+ */
+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);
+}
+
+/**
+ * Reads a vector of char16_t from the next location in a non-null parcel.
+ */
+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 an optional vector of char16_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::optional<std::vector<char16_t>>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readCharArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<char16_t>);
+}
+
+/**
+ * Writes a vector of int8_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int8_t>& vec) {
+ return AParcel_writeByteArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of int8_t to the next location in a non-null parcel.
+ */
+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);
+}
+
+/**
+ * Reads a vector of int8_t from the next location in a non-null parcel.
+ */
+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>);
+}
+
+/**
+ * Reads an optional vector of int8_t from the next location in a non-null parcel.
+ */
+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>
@@ -309,6 +739,23 @@
}
/**
+ * 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>
@@ -323,6 +770,28 @@
return STATUS_OK;
}
+/**
+ * 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;
+}
+
} // namespace ndk
/** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 7a75942..41df90b 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -39,7 +39,6 @@
AParcel_readInt32Array;
AParcel_readInt64;
AParcel_readInt64Array;
- AParcel_readNullableStrongBinder;
AParcel_readParcelFileDescriptor;
AParcel_readStatusHeader;
AParcel_readString;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 8e5b477..3c32100 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -36,28 +36,46 @@
using ::android::os::ParcelFileDescriptor;
template <typename T>
-using ContiguousArrayAllocator = T* (*)(void* arrayData, size_t length);
+using ContiguousArrayAllocator = bool (*)(void* arrayData, int32_t length, T** outBuffer);
template <typename T>
-using ArrayAllocator = bool (*)(void* arrayData, size_t length);
+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);
@@ -67,17 +85,16 @@
// 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]);
@@ -96,10 +113,12 @@
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;
- T* array = allocator(arrayData, length);
- if (length == 0) return STATUS_OK;
+ T* array;
+ if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+
+ if (length <= 0) return STATUS_OK;
if (array == nullptr) return STATUS_NO_MEMORY;
int32_t size = 0;
@@ -123,10 +142,12 @@
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;
- char16_t* array = allocator(arrayData, length);
- if (length == 0) return STATUS_OK;
+ char16_t* array;
+ if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+
+ if (length <= 0) return STATUS_OK;
if (array == nullptr) return STATUS_NO_MEMORY;
int32_t size = 0;
@@ -142,15 +163,16 @@
}
template <typename T>
-binder_status_t WriteArray(AParcel* parcel, const void* arrayData, size_t length,
+binder_status_t WriteArray(AParcel* parcel, const void* arrayData, int32_t length,
ArrayGetter<T> getter, status_t (Parcel::*write)(T)) {
- if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
+ // 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));
@@ -169,10 +191,12 @@
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;
+ if (length <= 0) return STATUS_OK;
+
for (size_t i = 0; i < length; i++) {
T readTarget;
status = (rawParcel->*read)(&readTarget);
@@ -194,17 +218,6 @@
}
binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder) {
sp<IBinder> readBinder = nullptr;
- status_t status = parcel->get()->readStrongBinder(&readBinder);
- if (status != STATUS_OK) {
- return PruneStatusT(status);
- }
- sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(readBinder);
- AIBinder_incStrong(ret.get());
- *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);
@@ -216,23 +229,39 @@
}
binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd) {
- ParcelFileDescriptor parcelFd((unique_fd(fd)));
+ std::unique_ptr<ParcelFileDescriptor> parcelFd;
- status_t status = parcel->get()->writeParcelable(parcelFd);
+ if (fd < 0) {
+ if (fd != -1) {
+ return STATUS_UNKNOWN_ERROR;
+ }
+ // parcelFd = nullptr
+ } else { // fd >= 0
+ parcelFd = std::make_unique<ParcelFileDescriptor>(unique_fd(fd));
+ }
+
+ status_t status = parcel->get()->writeNullableParcelable(parcelFd);
// ownership is retained by caller
- (void)parcelFd.release().release();
+ if (parcelFd != nullptr) {
+ (void)parcelFd->release().release();
+ }
return PruneStatusT(status);
}
binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd) {
- ParcelFileDescriptor parcelFd;
- // status_t status = parcelFd.readFromParcel(parcel->get());
+ std::unique_ptr<ParcelFileDescriptor> parcelFd;
+
status_t status = parcel->get()->readParcelable(&parcelFd);
if (status != STATUS_OK) return PruneStatusT(status);
- *fd = parcelFd.release().release();
+ if (parcelFd) {
+ *fd = parcelFd->release().release();
+ } else {
+ *fd = -1;
+ }
+
return STATUS_OK;
}
@@ -248,9 +277,23 @@
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()) {
@@ -279,7 +322,10 @@
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;
}
@@ -296,9 +342,10 @@
return STATUS_BAD_VALUE;
}
- char* str8 = allocator(stringData, len8);
+ char* str8;
+ bool success = allocator(stringData, len8, &str8);
- if (str8 == nullptr) {
+ if (!success || str8 == nullptr) {
LOG(WARNING) << __func__ << ": AParcel_stringAllocator failed to allocate.";
return STATUS_NO_MEMORY;
}
@@ -308,19 +355,18 @@
return STATUS_OK;
}
-binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, size_t length,
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length,
AParcel_stringArrayElementGetter getter) {
- 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);
+ // 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) return STATUS_BAD_VALUE;
+ if (str == nullptr && length != -1) return STATUS_BAD_VALUE;
binder_status_t status = AParcel_writeString(parcel, str, length);
if (status != STATUS_OK) return status;
@@ -336,10 +382,10 @@
size_t index; // index into the string array
AParcel_stringArrayElementAllocator elementAllocator;
- static char* Allocator(void* stringData, size_t length) {
+ static bool Allocator(void* stringData, int32_t length, char** buffer) {
StringArrayElementAllocationAdapter* adapter =
static_cast<StringArrayElementAllocationAdapter*>(stringData);
- return adapter->elementAllocator(adapter->arrayData, adapter->index, length);
+ return adapter->elementAllocator(adapter->arrayData, adapter->index, length, buffer);
}
};
@@ -352,10 +398,12 @@
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;
+ if (length == -1) return STATUS_OK; // null string array
+
StringArrayElementAllocationAdapter adapter{
.arrayData = arrayData,
.index = 0,
@@ -363,8 +411,10 @@
};
for (; adapter.index < length; adapter.index++) {
- AParcel_readString(parcel, static_cast<void*>(&adapter),
- StringArrayElementAllocationAdapter::Allocator);
+ binder_status_t status = AParcel_readString(parcel, static_cast<void*>(&adapter),
+ StringArrayElementAllocationAdapter::Allocator);
+
+ if (status != STATUS_OK) return status;
}
return STATUS_OK;
@@ -463,42 +513,42 @@
return PruneStatusT(status);
}
-binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, size_t 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* arrayData,
- size_t length) {
+ int32_t length) {
return WriteArray<uint32_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, size_t 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* arrayData,
- size_t length) {
+ int32_t length) {
return WriteArray<uint64_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, size_t 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* arrayData, size_t 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, size_t length,
+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* arrayData, size_t 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* arrayData, size_t length) {
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, int32_t length) {
return WriteArray<int8_t>(parcel, arrayData, length);
}
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
index bb76254..8f587d2 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -99,8 +99,8 @@
for pretty, cpp in data_types:
nca = pretty in non_contiguously_addressable
- arg_types = "const " + cpp + "* arrayData, size_t length"
- if nca: arg_types = "const void* arrayData, size_t length, AParcel_" + pretty.lower() + "ArrayGetter getter"
+ 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
@@ -114,11 +114,11 @@
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.\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'.\n"
- header += " * \\param length the length of arrayData.\n"
+ 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"
@@ -139,16 +139,16 @@
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.\n"
+ 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.\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, size_t length);\n\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"
@@ -178,16 +178,18 @@
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.\n"
+ 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 a buffer of " + cpp + " of size 'length'.\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 " + cpp + "* (*" + allocator_type + ")(void* arrayData, size_t length);\n\n"
+ pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, int32_t length, " + cpp + "** outBuffer);\n\n"
read_array_args = [("const AParcel*", "parcel")]
read_array_args += [("void*", "arrayData")]
@@ -232,6 +234,16 @@
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 += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n"
@@ -247,6 +259,22 @@
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"]
+ 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"
+
replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", pre_header, "START-PRIMITIVE-VECTOR-GETTERS", "END-PRIMITIVE-VECTOR-GETTERS")
replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header, "START-PRIMITIVE-READ-WRITE", "END-PRIMITIVE-READ-WRITE")
replaceFileTags(ROOT + "parcel.cpp", source, "START", "END")
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index b29b6e7..67481cf 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -22,6 +22,7 @@
strip: {
none: true,
},
+ cpp_std: "c++17",
cflags: [
"-O0",
"-g",
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 7bcfffd..22c1bad 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -953,7 +953,7 @@
{
status_t ret;
Parcel data, reply;
- uid_t previousWorkSource = IPCThreadState::self()->setWorkSource(100);
+ int64_t previousWorkSource = IPCThreadState::self()->setCallingWorkSourceUid(100);
data.writeInterfaceToken(binderLibTestServiceName);
ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
EXPECT_EQ(100, reply.readInt32());
@@ -966,8 +966,8 @@
status_t ret;
Parcel data, reply;
- IPCThreadState::self()->setWorkSource(100);
- uid_t previousWorkSource = IPCThreadState::self()->clearWorkSource();
+ IPCThreadState::self()->setCallingWorkSourceUid(100);
+ int64_t previousWorkSource = IPCThreadState::self()->clearCallingWorkSource();
data.writeInterfaceToken(binderLibTestServiceName);
ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
@@ -976,6 +976,22 @@
EXPECT_EQ(NO_ERROR, ret);
}
+TEST_F(BinderLibTest, WorkSourceRestored)
+{
+ status_t ret;
+ Parcel data, reply;
+
+ IPCThreadState::self()->setCallingWorkSourceUid(100);
+ int64_t token = IPCThreadState::self()->clearCallingWorkSource();
+ IPCThreadState::self()->restoreCallingWorkSource(token);
+
+ data.writeInterfaceToken(binderLibTestServiceName);
+ ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+
+ EXPECT_EQ(100, reply.readInt32());
+ EXPECT_EQ(NO_ERROR, ret);
+}
+
class BinderLibTestService : public BBinder
{
public:
@@ -1276,7 +1292,7 @@
}
case BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION: {
data.enforceInterface(binderLibTestServiceName);
- reply->writeInt32(IPCThreadState::self()->getWorkSource());
+ reply->writeInt32(IPCThreadState::self()->getCallingWorkSourceUid());
return NO_ERROR;
}
default:
diff --git a/libs/binder/tests/binderValueTypeTest.cpp b/libs/binder/tests/binderValueTypeTest.cpp
index c8f4697..15949d4 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/renderengine/gl/GLES20RenderEngine.cpp b/libs/renderengine/gl/GLES20RenderEngine.cpp
index 70a4322..e244a83 100644
--- a/libs/renderengine/gl/GLES20RenderEngine.cpp
+++ b/libs/renderengine/gl/GLES20RenderEngine.cpp
@@ -275,6 +275,8 @@
// now figure out what version of GL did we actually get
// NOTE: a dummy surface is not needed if KHR_create_context is supported
+ // TODO(alecmouri): don't create this surface if EGL_KHR_surfaceless_context
+ // is supported.
EGLConfig dummyConfig = config;
if (dummyConfig == EGL_NO_CONFIG) {
@@ -301,10 +303,10 @@
break;
case GLES_VERSION_2_0:
case GLES_VERSION_3_0:
- engine = std::make_unique<GLES20RenderEngine>(featureFlags);
+ engine = std::make_unique<GLES20RenderEngine>(featureFlags, display, config, ctxt,
+ dummy);
break;
}
- engine->setEGLHandles(display, config, ctxt);
ALOGI("OpenGL ES informations:");
ALOGI("vendor : %s", extensions.getVendor());
@@ -314,9 +316,6 @@
ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
- eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglDestroySurface(display, dummy);
-
return engine;
}
@@ -359,11 +358,13 @@
return config;
}
-GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags)
+GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
+ EGLContext ctxt, EGLSurface dummy)
: renderengine::impl::RenderEngine(featureFlags),
- mEGLDisplay(EGL_NO_DISPLAY),
- mEGLConfig(nullptr),
- mEGLContext(EGL_NO_CONTEXT),
+ mEGLDisplay(display),
+ mEGLConfig(config),
+ mEGLContext(ctxt),
+ mDummySurface(dummy),
mVpWidth(0),
mVpHeight(0),
mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
@@ -636,12 +637,6 @@
// back to main framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
- // Workaround for b/77935566 to force the EGL driver to release the
- // screenshot buffer
- setScissor(Rect::EMPTY_RECT);
- clearWithColor(0.0, 0.0, 0.0, 0.0);
- disableScissor();
}
void GLES20RenderEngine::checkErrors() const {
@@ -974,12 +969,6 @@
return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer;
}
-void GLES20RenderEngine::setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt) {
- mEGLDisplay = display;
- mEGLConfig = config;
- mEGLContext = ctxt;
-}
-
} // namespace gl
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/gl/GLES20RenderEngine.h b/libs/renderengine/gl/GLES20RenderEngine.h
index 148df2f..aebb319 100644
--- a/libs/renderengine/gl/GLES20RenderEngine.h
+++ b/libs/renderengine/gl/GLES20RenderEngine.h
@@ -47,7 +47,8 @@
static std::unique_ptr<GLES20RenderEngine> create(int hwcFormat, uint32_t featureFlags);
static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
- GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
+ GLES20RenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
+ EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy);
~GLES20RenderEngine() override;
std::unique_ptr<Framebuffer> createFramebuffer() override;
@@ -120,11 +121,12 @@
// with PQ or HLG transfer function.
bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
bool needsXYZTransformMatrix() const;
- void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt);
+ void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy);
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
EGLContext mEGLContext;
+ EGLSurface mDummySurface;
GLuint mProtectedTexName;
GLint mMaxViewportDims[2];
GLint mMaxTextureSize;
diff --git a/opengl/include/EGL/Platform.h b/opengl/include/EGL/Platform.h
index 624d31f..f2b501c 100644
--- a/opengl/include/EGL/Platform.h
+++ b/opengl/include/EGL/Platform.h
@@ -36,6 +36,7 @@
namespace angle
{
struct WorkaroundsD3D;
+struct FeaturesVk;
using TraceEventHandle = uint64_t;
using EGLDisplayType = void *;
struct PlatformMethods;
@@ -233,6 +234,13 @@
{
}
+using OverrideFeaturesVkFunc = void (*)(PlatformMethods *platform,
+ angle::FeaturesVk *workaroundsVulkan);
+inline void DefaultOverrideFeaturesVk(PlatformMethods *platform,
+ angle::FeaturesVk *workaroundsVulkan)
+{
+}
+
// Callback on a successful program link with the program binary. Can be used to store
// shaders to disk. Keys are a 160-bit SHA-1 hash.
using ProgramKeyType = std::array<uint8_t, 20>;
@@ -262,6 +270,7 @@
OP(histogramSparse, HistogramSparse) \
OP(histogramBoolean, HistogramBoolean) \
OP(overrideWorkaroundsD3D, OverrideWorkaroundsD3D) \
+ OP(overrideFeaturesVk, OverrideFeaturesVk) \
OP(cacheProgram, CacheProgram)
#define ANGLE_PLATFORM_METHOD_DEF(Name, CapsName) CapsName##Func Name = Default##CapsName;
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
index 8b43333..28a7501 100644
--- a/services/bufferhub/Android.bp
+++ b/services/bufferhub/Android.bp
@@ -25,6 +25,7 @@
"BufferClient.cpp",
"BufferHubService.cpp",
"BufferNode.cpp",
+ "UniqueIdGenerator.cpp",
],
header_libs: [
"libbufferhub_headers",
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index 3bfd9cb..fc5ad1d 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -35,7 +35,7 @@
std::shared_ptr<BufferNode> node =
std::make_shared<BufferNode>(desc.width, desc.height, desc.layers, desc.format,
- desc.usage, userMetadataSize);
+ desc.usage, userMetadataSize, nodeIdGenerator.getId());
if (node == nullptr || !node->IsValid()) {
ALOGE("%s: creating BufferNode failed.", __FUNCTION__);
_hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::ALLOCATION_FAILED);
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index 53dd702..715d0a1 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -1,5 +1,6 @@
#include <errno.h>
+#include <bufferhub/BufferHubService.h>
#include <bufferhub/BufferNode.h>
#include <private/dvr/buffer_hub_defs.h>
#include <ui/GraphicBufferAllocator.h>
@@ -22,7 +23,8 @@
// Allocates a new BufferNode.
BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t user_metadata_size) {
+ uint64_t usage, size_t user_metadata_size, uint32_t id)
+ : mId(id) {
uint32_t out_stride = 0;
// graphicBufferId is not used in GraphicBufferAllocator::allocate
// TODO(b/112338294) After move to the service folder, stop using the
@@ -54,14 +56,23 @@
InitializeMetadata();
}
-// Free the handle
BufferNode::~BufferNode() {
+ // Free the handle
if (buffer_handle_ != nullptr) {
status_t ret = GraphicBufferAllocator::get().free(buffer_handle_);
if (ret != OK) {
ALOGE("%s: Failed to free handle; Got error: %d", __FUNCTION__, ret);
}
}
+
+ // Free the id, if valid
+ if (id() != UniqueIdGenerator::kInvalidId) {
+ if (nodeIdGenerator.freeId(id())) {
+ ALOGI("%s: id #%u is freed.", __FUNCTION__, id());
+ } else {
+ ALOGE("%s: Cannot free nonexistent id #%u", __FUNCTION__, id());
+ }
+ }
}
uint64_t BufferNode::GetActiveClientsBitMask() const {
diff --git a/services/bufferhub/UniqueIdGenerator.cpp b/services/bufferhub/UniqueIdGenerator.cpp
new file mode 100644
index 0000000..362a026
--- /dev/null
+++ b/services/bufferhub/UniqueIdGenerator.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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 <bufferhub/UniqueIdGenerator.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+constexpr uint32_t UniqueIdGenerator::kInvalidId;
+
+uint32_t UniqueIdGenerator::getId() {
+ std::lock_guard<std::mutex> lock(mIdsInUseMutex);
+
+ do {
+ if (++mLastId >= std::numeric_limits<uint32_t>::max()) {
+ mLastId = kInvalidId + 1;
+ }
+ } while (mIdsInUse.find(mLastId) != mIdsInUse.end());
+
+ mIdsInUse.insert(mLastId);
+ return mLastId;
+}
+
+bool UniqueIdGenerator::freeId(uint32_t id) {
+ std::lock_guard<std::mutex> lock(mIdsInUseMutex);
+ auto iter = mIdsInUse.find(id);
+ if (iter != mIdsInUse.end()) {
+ mIdsInUse.erase(iter);
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
index dbbee8f..5441750 100644
--- a/services/bufferhub/include/bufferhub/BufferHubService.h
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -22,6 +22,7 @@
#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
#include <bufferhub/BufferClient.h>
+#include <bufferhub/UniqueIdGenerator.h>
#include <utils/Mutex.h>
namespace android {
@@ -34,6 +35,8 @@
using hardware::Return;
using hardware::graphics::common::V1_2::HardwareBufferDescription;
+static UniqueIdGenerator nodeIdGenerator;
+
class BufferHubService : public IBufferHub {
public:
Return<void> allocateBuffer(const HardwareBufferDescription& description,
diff --git a/services/bufferhub/include/bufferhub/BufferNode.h b/services/bufferhub/include/bufferhub/BufferNode.h
index ffeacac..c490e7c 100644
--- a/services/bufferhub/include/bufferhub/BufferNode.h
+++ b/services/bufferhub/include/bufferhub/BufferNode.h
@@ -2,6 +2,7 @@
#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_NODE_H_
#include <android/hardware_buffer.h>
+#include <bufferhub/UniqueIdGenerator.h>
#include <ui/BufferHubMetadata.h>
namespace android {
@@ -14,13 +15,16 @@
public:
// Allocates a new BufferNode.
BufferNode(uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t user_metadata_size);
+ uint64_t usage, size_t user_metadata_size,
+ uint32_t id = UniqueIdGenerator::kInvalidId);
~BufferNode();
// Returns whether the object holds a valid metadata.
bool IsValid() const { return metadata_.IsValid(); }
+ uint32_t id() const { return mId; }
+
size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
// Accessors of the buffer description and handle
@@ -59,6 +63,11 @@
// Metadata in shared memory.
BufferHubMetadata metadata_;
+ // A system-unique id generated by bufferhub from 1 to std::numeric_limits<uint32_t>::max().
+ // BufferNodes not created by bufferhub will have id = 0, meaning "not specified".
+ // TODO(b/118891412): remove default id = 0 and update comments after pdx is no longer in use
+ const uint32_t mId = 0;
+
// The following variables are atomic variables in metadata_ that are visible
// to Bn object and Bp objects. Please find more info in
// BufferHubDefs::MetadataHeader.
diff --git a/services/bufferhub/include/bufferhub/UniqueIdGenerator.h b/services/bufferhub/include/bufferhub/UniqueIdGenerator.h
new file mode 100644
index 0000000..d2e702f
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/UniqueIdGenerator.h
@@ -0,0 +1,57 @@
+/*
+ * 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_FRAMEWORKS_BUFFERHUB_V1_0_ID_GENERATOR_H
+#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_ID_GENERATOR_H
+
+#include <mutex>
+#include <set>
+
+#include <utils/Mutex.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+// A thread-safe incremental uint32_t id generator.
+class UniqueIdGenerator {
+public:
+ // 0 is considered invalid
+ static constexpr uint32_t kInvalidId = 0UL;
+
+ // Gets next available id. If next id is greater than std::numeric_limits<uint32_t>::max() (2 ^
+ // 32 - 1), it will try to get an id start from 1 again.
+ uint32_t getId();
+
+ // Free a specific id. Return true on freed, false on not found.
+ bool freeId(uint32_t id);
+
+private:
+ std::mutex mIdsInUseMutex;
+ // Start from kInvalidID to avoid generating it.
+ uint32_t mLastId = kInvalidId;
+ std::set<uint32_t> mIdsInUse GUARDED_BY(mIdsInUseMutex);
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
+
+#endif // ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_ID_GENERATOR_H
diff --git a/services/bufferhub/tests/Android.bp b/services/bufferhub/tests/Android.bp
index cef31f6..8a30ef5 100644
--- a/services/bufferhub/tests/Android.bp
+++ b/services/bufferhub/tests/Android.bp
@@ -21,4 +21,20 @@
],
// TODO(b/117568153): Temporarily opt out using libcrt.
no_libcrt: true,
+}
+
+cc_test {
+ name: "UniqueIdGenerator_test",
+ srcs: ["UniqueIdGenerator_test.cpp"],
+ cflags: [
+ "-DLOG_TAG=\"UniqueIdGenerator_test\"",
+ "-DTRACE=0",
+ "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
+ ],
+ shared_libs: [
+ "libbufferhubservice",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
}
\ No newline at end of file
diff --git a/services/bufferhub/tests/UniqueIdGenerator_test.cpp b/services/bufferhub/tests/UniqueIdGenerator_test.cpp
new file mode 100644
index 0000000..c4d83e0
--- /dev/null
+++ b/services/bufferhub/tests/UniqueIdGenerator_test.cpp
@@ -0,0 +1,45 @@
+#include <bufferhub/UniqueIdGenerator.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+namespace {
+
+class UniqueIdGeneratorTest : public testing::Test {
+protected:
+ UniqueIdGenerator mIdGenerator;
+};
+
+TEST_F(UniqueIdGeneratorTest, TestGenerateAndFreeID) {
+ uint32_t id = mIdGenerator.getId();
+ EXPECT_NE(id, UniqueIdGenerator::kInvalidId);
+
+ EXPECT_TRUE(mIdGenerator.freeId(id));
+ EXPECT_FALSE(mIdGenerator.freeId(id));
+}
+
+TEST_F(UniqueIdGeneratorTest, TestGenerateUniqueIncrementalID) {
+ // 10 IDs should not overflow the UniqueIdGenerator to cause a roll back to start, so the
+ // resulting IDs should still keep incresing.
+ const size_t kTestSize = 10U;
+ uint32_t ids[kTestSize];
+ for (int i = 0; i < kTestSize; ++i) {
+ ids[i] = mIdGenerator.getId();
+ EXPECT_NE(ids[i], UniqueIdGenerator::kInvalidId);
+ if (i >= 1) {
+ EXPECT_GT(ids[i], ids[i - 1]);
+ }
+ }
+}
+
+} // namespace
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
\ No newline at end of file
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index e4ca6bc..150896c 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -62,7 +62,7 @@
status_t cmd_vkjson(int out, int err);
}
-const char* const GpuService::SERVICE_NAME = "gpuservice";
+const char* const GpuService::SERVICE_NAME = "gpu";
GpuService::GpuService() = default;
diff --git a/services/gpuservice/gpuservice.rc b/services/gpuservice/gpuservice.rc
index d23cf46..65a5c27 100644
--- a/services/gpuservice/gpuservice.rc
+++ b/services/gpuservice/gpuservice.rc
@@ -1,4 +1,4 @@
-service gpuservice /system/bin/gpuservice
+service gpu /system/bin/gpuservice
class core
user gpu_service
group graphics
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index f168db9..9abb040 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -184,6 +184,7 @@
"libhidltransport",
"liblayers_proto",
"liblog",
+ "libsync",
"libtimestats_proto",
"libutils",
],
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 5342bcf..55ce434 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -35,6 +35,8 @@
#include <gui/Surface.h>
#include <hardware/gralloc.h>
#include <renderengine/RenderEngine.h>
+#include <sync/sync.h>
+#include <system/window.h>
#include <ui/DebugUtils.h>
#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
@@ -221,6 +223,7 @@
mDisplayToken(args.displayToken),
mId(args.displayId),
mNativeWindow(args.nativeWindow),
+ mGraphicBuffer(nullptr),
mDisplaySurface(args.displaySurface),
mSurface{std::move(args.renderSurface)},
mDisplayInstallOrientation(args.displayInstallOrientation),
@@ -284,6 +287,14 @@
mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
ANativeWindow* const window = mNativeWindow.get();
+
+ int status = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ ALOGE_IF(status != NO_ERROR, "Unable to connect BQ producer: %d", status);
+ status = native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ format to RGBA888: %d", status);
+ status = native_window_set_usage(window, GRALLOC_USAGE_HW_RENDER);
+ ALOGE_IF(status != NO_ERROR, "Unable to set BQ usage bits for GPU rendering: %d", status);
+
mDisplayWidth = ANativeWindow_getWidth(window);
mDisplayHeight = ANativeWindow_getHeight(window);
@@ -321,7 +332,6 @@
void DisplayDevice::flip() const
{
- mFlinger->getRenderEngine().checkErrors();
mPageFlipCount++;
}
@@ -356,9 +366,71 @@
return mDisplaySurface->prepareFrame(compositionType);
}
-void DisplayDevice::swapBuffers(HWComposer& hwc) const {
+sp<GraphicBuffer> DisplayDevice::dequeueBuffer() {
+ int fd;
+ ANativeWindowBuffer* buffer;
+
+ status_t res = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fd);
+
+ if (res != NO_ERROR) {
+ ALOGE("ANativeWindow::dequeueBuffer failed for display [%s] with error: %d",
+ getDisplayName().c_str(), res);
+ // Return fast here as we can't do much more - any rendering we do
+ // now will just be wrong.
+ return mGraphicBuffer;
+ }
+
+ ALOGW_IF(mGraphicBuffer != nullptr, "Clobbering a non-null pointer to a buffer [%p].",
+ mGraphicBuffer->getNativeBuffer()->handle);
+ mGraphicBuffer = GraphicBuffer::from(buffer);
+
+ // Block until the buffer is ready
+ // TODO(alecmouri): it's perhaps more appropriate to block renderengine so
+ // that the gl driver can block instead.
+ if (fd >= 0) {
+ sync_wait(fd, -1);
+ close(fd);
+ }
+
+ return mGraphicBuffer;
+}
+
+void DisplayDevice::queueBuffer(HWComposer& hwc) {
if (hwc.hasClientComposition(mId) || hwc.hasFlipClientTargetRequest(mId)) {
- mSurface->swapBuffers();
+ // hasFlipClientTargetRequest could return true even if we haven't
+ // dequeued a buffer before. Try dequeueing one if we don't have a
+ // buffer ready.
+ if (mGraphicBuffer == nullptr) {
+ ALOGI("Attempting to queue a client composited buffer without one "
+ "previously dequeued for display [%s]. Attempting to dequeue "
+ "a scratch buffer now",
+ mDisplayName.c_str());
+ // We shouldn't deadlock here, since mGraphicBuffer == nullptr only
+ // after a successful call to queueBuffer, or if dequeueBuffer has
+ // never been called.
+ dequeueBuffer();
+ }
+
+ if (mGraphicBuffer == nullptr) {
+ ALOGE("No buffer is ready for display [%s]", mDisplayName.c_str());
+ } else {
+ int fd = mBufferReady.release();
+
+ status_t res = mNativeWindow->queueBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(), fd);
+ if (res != NO_ERROR) {
+ ALOGE("Error when queueing buffer for display [%s]: %d", mDisplayName.c_str(), res);
+ // We risk blocking on dequeueBuffer if the primary display failed
+ // to queue up its buffer, so crash here.
+ if (isPrimary()) {
+ LOG_ALWAYS_FATAL("ANativeWindow::queueBuffer failed with error: %d", res);
+ } else {
+ mNativeWindow->cancelBuffer(mNativeWindow.get(),
+ mGraphicBuffer->getNativeBuffer(), fd);
+ }
+ }
+ mGraphicBuffer = nullptr;
+ }
}
status_t result = mDisplaySurface->advanceFrame();
@@ -367,7 +439,7 @@
}
}
-void DisplayDevice::onSwapBuffersCompleted() const {
+void DisplayDevice::onPresentDisplayCompleted() {
mDisplaySurface->onFrameCommitted();
}
@@ -384,6 +456,13 @@
mFlinger->getRenderEngine().setViewportAndProjection(w, h, sourceCrop, ui::Transform::ROT_0);
}
+void DisplayDevice::finishBuffer() {
+ mBufferReady = mFlinger->getRenderEngine().flush();
+ if (mBufferReady.get() < 0) {
+ mFlinger->getRenderEngine().finish();
+ }
+}
+
const sp<Fence>& DisplayDevice::getClientTargetAcquireFence() const {
return mDisplaySurface->getClientTargetAcquireFence();
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index bcd3330..560a958 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -28,13 +28,14 @@
#include <gui/LayerState.h>
#include <hardware/hwcomposer_defs.h>
#include <math/mat4.h>
+#include <renderengine/RenderEngine.h>
#include <renderengine/Surface.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
#include <ui/Transform.h>
-#include <utils/RefBase.h>
#include <utils/Mutex.h>
+#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/Timers.h>
@@ -146,10 +147,13 @@
ui::Dataspace* outDataspace, ui::ColorMode* outMode,
ui::RenderIntent* outIntent) const;
- void swapBuffers(HWComposer& hwc) const;
+ // Queues the drawn buffer for consumption by HWC.
+ void queueBuffer(HWComposer& hwc);
+ // Allocates a buffer as scratch space for GPU composition
+ sp<GraphicBuffer> dequeueBuffer();
// called after h/w composer has completed its set() call
- void onSwapBuffersCompleted() const;
+ void onPresentDisplayCompleted();
Rect getBounds() const {
return Rect(mDisplayWidth, mDisplayHeight);
@@ -160,6 +164,11 @@
const std::string& getDisplayName() const { return mDisplayName; }
bool makeCurrent() const;
+ // Acquires a new buffer for GPU composition.
+ void readyNewBuffer();
+ // Marks the current buffer has finished, so that it can be presented and
+ // swapped out.
+ void finishBuffer();
void setViewportAndProjection() const;
const sp<Fence>& getClientTargetAcquireFence() const;
@@ -204,7 +213,12 @@
// ANativeWindow this display is rendering into
sp<ANativeWindow> mNativeWindow;
+ // Current buffer that this display can render to.
+ sp<GraphicBuffer> mGraphicBuffer;
sp<DisplaySurface> mDisplaySurface;
+ // File descriptor indicating that mGraphicBuffer is ready for display, i.e.
+ // that drawing to the buffer is now complete.
+ base::unique_fd mBufferReady;
std::unique_ptr<renderengine::Surface> mSurface;
int mDisplayWidth;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 038bc58..1e910ce 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1344,7 +1344,10 @@
void Layer::updateTransformHint(const sp<const DisplayDevice>& display) const {
uint32_t orientation = 0;
- if (!mFlinger->mDebugDisableTransformHint) {
+ // Disable setting transform hint if the debug flag is set or if the
+ // getTransformToDisplayInverse flag is set and the client wants to submit buffers
+ // in one orientation.
+ if (!mFlinger->mDebugDisableTransformHint && !getTransformToDisplayInverse()) {
// The transform hint is used to improve performance, but we can
// only have a single transform hint, it cannot
// apply to all displays.
@@ -1976,6 +1979,7 @@
layerInfo->set_window_type(state.type);
layerInfo->set_app_id(state.appId);
layerInfo->set_curr_frame(mCurrentFrameNumber);
+ layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
for (const auto& pendingState : mPendingStates) {
auto barrierLayer = pendingState.barrierLayer_legacy.promote();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 35ba391..7150660 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -45,6 +45,7 @@
#include <gui/BufferQueue.h>
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
+#include <gui/IProducerListener.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
#include <renderengine/RenderEngine.h>
@@ -676,10 +677,6 @@
LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(*display->getId()),
"Internal display is disconnected.");
- // make the default display GLContext current so that we can create textures
- // when creating Layers (which may happens before we render something)
- display->makeCurrent();
-
if (useVrFlinger) {
auto vrFlingerRequestDisplayCallback = [this](bool requestDisplay) {
// This callback is called from the vr flinger dispatch thread. We
@@ -1409,7 +1406,6 @@
// mCurrentState and mDrawingState and re-apply all changes when we make the
// transition.
mDrawingState.displays.clear();
- getRenderEngine().resetCurrentSurface();
mDisplays.clear();
}
@@ -1719,7 +1715,7 @@
auto& engine(getRenderEngine());
engine.fillRegionWithColor(dirtyRegion, 1, 0, 1, 1);
- display->swapBuffers(getHwComposer());
+ display->queueBuffer(getHwComposer());
}
}
@@ -2194,8 +2190,7 @@
if (displayId) {
getHwComposer().presentAndGetReleaseFences(*displayId);
}
- display->onSwapBuffersCompleted();
- display->makeCurrent();
+ display->onPresentDisplayCompleted();
for (auto& layer : display->getVisibleLayersSortedByZ()) {
sp<Fence> releaseFence = Fence::NO_FENCE;
@@ -2348,16 +2343,11 @@
std::unique_ptr<renderengine::Surface> renderSurface = getRenderEngine().createSurface();
renderSurface->setCritical(isInternalDisplay);
renderSurface->setAsync(state.isVirtual());
- renderSurface->setNativeWindow(nativeWindow.get());
creationArgs.renderSurface = std::move(renderSurface);
// Make sure that composition can never be stalled by a virtual display
// consumer that isn't processing buffers fast enough. We have to do this
- // in two places:
- // * Here, in case the display is composed entirely by HWC.
- // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
- // window's swap interval in eglMakeCurrent, so they'll override the
- // interval we set here.
+ // here, in case the display is composed entirely by HWC.
if (state.isVirtual()) {
nativeWindow->setSwapInterval(nativeWindow.get(), 0);
}
@@ -2417,12 +2407,6 @@
const auto externalDisplayId = getExternalDisplayId();
// in drawing state but not in current state
- // Call makeCurrent() on the primary display so we can
- // be sure that nothing associated with this display
- // is current.
- if (const auto defaultDisplay = getDefaultDisplayDeviceLocked()) {
- defaultDisplay->makeCurrent();
- }
if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
display->disconnect(getHwComposer());
}
@@ -2973,7 +2957,7 @@
mGeometryInvalid = true;
}
-void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& display,
+void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& display,
const Region& inDirtyRegion) {
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
@@ -2988,10 +2972,10 @@
if (!doComposeSurfaces(display)) return;
// swap buffers (presentation)
- display->swapBuffers(getHwComposer());
+ display->queueBuffer(getHwComposer());
}
-bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& display) {
+bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& display) {
ALOGV("doComposeSurfaces");
const Region bounds(display->bounds());
@@ -3004,9 +2988,31 @@
bool applyColorMatrix = false;
bool needsEnhancedColorMatrix = false;
+ // Framebuffer will live in this scope for GPU composition.
+ std::unique_ptr<renderengine::BindNativeBufferAsFramebuffer> fbo;
+
if (hasClientComposition) {
ALOGV("hasClientComposition");
+ sp<GraphicBuffer> buf = display->dequeueBuffer();
+
+ if (buf == nullptr) {
+ ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
+ "client composition for this frame",
+ display->getDisplayName().c_str());
+ return false;
+ }
+
+ // Bind the framebuffer in this scope.
+ fbo = std::make_unique<renderengine::BindNativeBufferAsFramebuffer>(getRenderEngine(),
+ buf->getNativeBuffer());
+
+ if (fbo->getStatus() != NO_ERROR) {
+ ALOGW("Binding buffer for display [%s] failed with status: %d",
+ display->getDisplayName().c_str(), fbo->getStatus());
+ return false;
+ }
+
Dataspace outputDataspace = Dataspace::UNKNOWN;
if (display->hasWideColorGamut()) {
outputDataspace = display->getCompositionDataSpace();
@@ -3035,18 +3041,7 @@
colorMatrix *= mEnhancedSaturationMatrix;
}
- if (!display->makeCurrent()) {
- ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
- display->getDisplayName().c_str());
- getRenderEngine().resetCurrentSurface();
-
- // |mStateLock| not needed as we are on the main thread
- const auto defaultDisplay = getDefaultDisplayDeviceLocked();
- if (!defaultDisplay || !defaultDisplay->makeCurrent()) {
- ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
- }
- return false;
- }
+ display->setViewportAndProjection();
// Never touch the framebuffer if we don't have any framebuffer layers
if (hasDeviceComposition) {
@@ -3139,11 +3134,15 @@
firstLayer = false;
}
- // Clear color transform matrix at the end of the frame.
- getRenderEngine().setColorTransform(mat4());
-
- // disable scissor at the end of the frame
- getBE().mRenderEngine->disableScissor();
+ // Perform some cleanup steps if we used client composition.
+ if (hasClientComposition) {
+ getRenderEngine().setColorTransform(mat4());
+ getBE().mRenderEngine->disableScissor();
+ display->finishBuffer();
+ // Clear out error flags here so that we don't wait until next
+ // composition to log.
+ getRenderEngine().checkErrors();
+ }
return true;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8b389bc..f98dddf 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -721,10 +721,10 @@
void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
void doTracing(const char* where);
void logLayerStats();
- void doDisplayComposition(const sp<const DisplayDevice>& display, const Region& dirtyRegion);
+ void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion);
// This fails if using GL and the surface has been destroyed.
- bool doComposeSurfaces(const sp<const DisplayDevice>& display);
+ bool doComposeSurfaces(const sp<DisplayDevice>& display);
void postFramebuffer(const sp<DisplayDevice>& display);
void postFrame();
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index 67dcd06..1835929 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -26,22 +26,48 @@
namespace android {
-void SurfaceTracing::enable() {
- ATRACE_CALL();
+void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
+ // use the swap trick to make sure memory is released
+ std::queue<LayersTraceProto>().swap(mStorage);
+ mSizeInBytes = newSize;
+ mUsedInBytes = 0U;
+}
+
+void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) {
+ auto protoSize = proto.ByteSize();
+ while (mUsedInBytes + protoSize > mSizeInBytes) {
+ if (mStorage.empty()) {
+ return;
+ }
+ mUsedInBytes -= mStorage.front().ByteSize();
+ mStorage.pop();
+ }
+ mUsedInBytes += protoSize;
+ mStorage.emplace();
+ mStorage.back().Swap(&proto);
+}
+
+void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) {
+ fileProto->mutable_entry()->Reserve(mStorage.size());
+
+ while (!mStorage.empty()) {
+ auto entry = fileProto->add_entry();
+ entry->Swap(&mStorage.front());
+ mStorage.pop();
+ }
+}
+
+void SurfaceTracing::enable(size_t bufferSizeInByte) {
std::lock_guard<std::mutex> protoGuard(mTraceMutex);
if (mEnabled) {
return;
}
mEnabled = true;
-
- mTrace = std::make_unique<LayersTraceFileProto>();
- mTrace->set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
- LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
+ mBuffer.reset(bufferSizeInByte);
}
status_t SurfaceTracing::disable() {
- ATRACE_CALL();
std::lock_guard<std::mutex> protoGuard(mTraceMutex);
if (!mEnabled) {
@@ -51,7 +77,7 @@
status_t err(writeProtoFileLocked());
ALOGE_IF(err == PERMISSION_DENIED, "Could not save the proto file! Permission denied");
ALOGE_IF(err == NOT_ENOUGH_DATA, "Could not save the proto file! There are missing fields");
- mTrace.reset();
+ mBuffer.reset(0);
return err;
}
@@ -65,32 +91,29 @@
if (!mEnabled) {
return;
}
- LayersTraceProto* entry = mTrace->add_entry();
- entry->set_elapsed_realtime_nanos(elapsedRealtimeNano());
- entry->set_where(where);
- entry->mutable_layers()->Swap(&layers);
- constexpr int maxBufferedEntryCount = 3600;
- if (mTrace->entry_size() >= maxBufferedEntryCount) {
- // TODO: flush buffered entries without disabling tracing
- ALOGE("too many buffered frames; force disable tracing");
- mEnabled = false;
- writeProtoFileLocked();
- mTrace.reset();
- }
+ LayersTraceProto entry;
+ entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
+ entry.set_where(where);
+ entry.mutable_layers()->Swap(&layers);
+
+ mBuffer.emplace(std::move(entry));
}
status_t SurfaceTracing::writeProtoFileLocked() {
ATRACE_CALL();
- if (!mTrace->IsInitialized()) {
- return NOT_ENOUGH_DATA;
- }
+ LayersTraceFileProto fileProto;
std::string output;
- if (!mTrace->SerializeToString(&output)) {
+
+ fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
+ LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
+ mBuffer.flush(&fileProto);
+
+ if (!fileProto.SerializeToString(&output)) {
return PERMISSION_DENIED;
}
- if (!android::base::WriteStringToFile(output, mOutputFileName, true)) {
+ if (!android::base::WriteStringToFile(output, kDefaultFileName, true)) {
return PERMISSION_DENIED;
}
@@ -101,7 +124,8 @@
std::lock_guard<std::mutex> protoGuard(mTraceMutex);
result.appendFormat("Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
- result.appendFormat(" number of entries: %d\n", mTrace ? mTrace->entry_size() : 0);
+ result.appendFormat(" number of entries: %zu (%.2fMB / %.2fMB)\n", mBuffer.frameCount(),
+ float(mBuffer.used()) / float(1_MB), float(mBuffer.size()) / float(1_MB));
}
} // namespace android
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index fd8cb82..ec01be7 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -22,32 +22,54 @@
#include <memory>
#include <mutex>
+#include <queue>
using namespace android::surfaceflinger;
namespace android {
+constexpr auto operator""_MB(unsigned long long const num) {
+ return num * 1024 * 1024;
+}
+
/*
* SurfaceTracing records layer states during surface flinging.
*/
class SurfaceTracing {
public:
- void enable();
+ void enable() { enable(kDefaultBufferCapInByte); }
+ void enable(size_t bufferSizeInByte);
status_t disable();
- bool isEnabled() const;
-
void traceLayers(const char* where, LayersProto);
+
+ bool isEnabled() const;
void dump(String8& result) const;
private:
- static constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/layers_trace.pb";
+ static constexpr auto kDefaultBufferCapInByte = 100_MB;
+ static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb";
+
+ class LayersTraceBuffer { // ring buffer
+ public:
+ size_t size() const { return mSizeInBytes; }
+ size_t used() const { return mUsedInBytes; }
+ size_t frameCount() const { return mStorage.size(); }
+
+ void reset(size_t newSize);
+ void emplace(LayersTraceProto&& proto);
+ void flush(LayersTraceFileProto* fileProto);
+
+ private:
+ size_t mUsedInBytes = 0U;
+ size_t mSizeInBytes = 0U;
+ std::queue<LayersTraceProto> mStorage;
+ };
status_t writeProtoFileLocked();
bool mEnabled = false;
- std::string mOutputFileName = DEFAULT_FILENAME;
mutable std::mutex mTraceMutex;
- std::unique_ptr<LayersTraceFileProto> mTrace;
+ LayersTraceBuffer mBuffer;
};
} // namespace android
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 2a09634..c141ee3 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -86,6 +86,7 @@
repeated BarrierLayerProto barrier_layer = 38;
// If active_buffer is not null, record its transform.
optional TransformProto buffer_transform = 39;
+ optional int32 effective_scaling_mode = 40;
}
message PositionProto {
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index ab1b252..6d3e715 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -46,6 +46,7 @@
using testing::AtLeast;
using testing::ByMove;
using testing::DoAll;
+using testing::Invoke;
using testing::IsNull;
using testing::Mock;
using testing::NotNull;
@@ -142,6 +143,9 @@
renderengine::mock::Surface* mRenderSurface = new renderengine::mock::Surface();
mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
+ sp<GraphicBuffer> mBuffer = new GraphicBuffer();
+ ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
+
mock::EventThread* mEventThread = new mock::EventThread();
mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
@@ -266,13 +270,9 @@
EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
- EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
- .WillOnce(Return(true));
- EXPECT_CALL(*test->mRenderEngine,
- setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
- Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- ui::Transform::ROT_0))
- .Times(1);
+ EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() {
+ return base::unique_fd(0);
+ }));
EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
@@ -323,8 +323,6 @@
static void setupHwcCompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)).Times(1);
-
- EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
}
static void setupRECompositionCallExpectations(CompositionTest* test) {
@@ -344,12 +342,18 @@
setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
ui::Transform::ROT_0))
- .Times(1)
- .RetiresOnSaturation();
- EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
- .WillOnce(Return(true))
- .RetiresOnSaturation();
- EXPECT_CALL(*test->mRenderSurface, swapBuffers()).Times(1);
+ .Times(1);
+ EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull())).WillOnce(Return(true));
+ EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull())).WillOnce(Return(true));
+ EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
+ .WillOnce(Return(
+ ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer))));
+ EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1);
+ EXPECT_CALL(*test->mNativeWindow, queueBuffer(_, _)).WillOnce(Return(0));
+ EXPECT_CALL(*test->mNativeWindow, dequeueBuffer(_, _))
+ .WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1),
+ Return(0)));
}
template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 32fce67..e8c8894 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -120,6 +120,7 @@
mock::EventThread* mEventThread = new mock::EventThread();
mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
+ sp<GraphicBuffer> mBuffer = new GraphicBuffer();
// These mocks are created by the test, but are destroyed by SurfaceFlinger
// by virtue of being stored into a std::unique_ptr. However we still need
@@ -340,7 +341,6 @@
static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow())
.WillOnce(Return(test->mNativeWindow));
- EXPECT_CALL(*test->mNativeWindow, perform(19)).WillRepeatedly(Return(NO_ERROR));
// For simplicity, we only expect to create a single render surface for
// each test.
@@ -349,17 +349,15 @@
EXPECT_CALL(*test->mRenderEngine, createSurface())
.WillOnce(Return(ByMove(
std::unique_ptr<renderengine::Surface>(test->mRenderSurface))));
-
- // Creating a DisplayDevice requires getting default dimensions from the
- // native window.
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
+ // Creating a DisplayDevice requires getting default dimensions from the
+ // native window.
EXPECT_CALL(*test->mRenderSurface, setAsync(static_cast<bool>(ASYNC))).Times(1);
EXPECT_CALL(*test->mRenderSurface, setCritical(static_cast<bool>(CRITICAL))).Times(1);
- EXPECT_CALL(*test->mRenderSurface, setNativeWindow(test->mNativeWindow.get())).Times(1);
}
static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
@@ -1070,9 +1068,6 @@
// The call disable vsyncs
EXPECT_CALL(*mEventControlThread, setVsyncEnabled(false)).Times(1);
- // The call clears the current render engine surface
- EXPECT_CALL(*mRenderEngine, resetCurrentSurface());
-
// The call ends any display resyncs
EXPECT_CALL(*mPrimaryDispSync, endResync()).Times(1);
@@ -1132,6 +1127,9 @@
.WillRepeatedly(DoAll(SetArgPointee<1>(1080 /* arbitrary */), Return(0)));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(1920 /* arbitrary */), Return(0)));
+ EXPECT_CALL(*mNativeWindow, perform(9)).Times(1);
+ EXPECT_CALL(*mNativeWindow, perform(13)).Times(1);
+ EXPECT_CALL(*mNativeWindow, perform(30)).Times(1);
auto displayDevice = mInjector.inject();
displayDevice->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
@@ -1725,7 +1723,6 @@
EXPECT_CALL(*surface, setAsyncMode(true)).Times(1);
- EXPECT_CALL(*mProducer, connect(_, _, _, _)).Times(1);
EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1);
Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this);
@@ -1950,10 +1947,19 @@
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new mock::DisplaySurface();
auto renderSurface = new renderengine::mock::Surface();
+ sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
display.setRenderSurface(std::unique_ptr<renderengine::Surface>(renderSurface));
+ // Setup injection expections
+ EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
+ EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
+ EXPECT_CALL(*nativeWindow, perform(9)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(13)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(30)).Times(1);
display.inject();
// There is a change to the viewport state
@@ -1965,9 +1971,7 @@
// --------------------------------------------------------------------
// Call Expectations
- EXPECT_CALL(*renderSurface, setNativeWindow(nullptr)).Times(1);
EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1);
- EXPECT_CALL(*renderSurface, setNativeWindow(nativeWindow)).Times(1);
// --------------------------------------------------------------------
// Invocation
@@ -1989,10 +1993,19 @@
auto nativeWindow = new mock::NativeWindow();
auto displaySurface = new mock::DisplaySurface();
auto renderSurface = new renderengine::mock::Surface();
+ sp<GraphicBuffer> buf = new GraphicBuffer();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
display.setRenderSurface(std::unique_ptr<renderengine::Surface>(renderSurface));
+ // Setup injection expections
+ EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
+ EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
+ EXPECT_CALL(*nativeWindow, perform(9)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(13)).Times(1);
+ EXPECT_CALL(*nativeWindow, perform(30)).Times(1);
display.inject();
// There is a change to the viewport state
@@ -2004,9 +2017,7 @@
// --------------------------------------------------------------------
// Call Expectations
- EXPECT_CALL(*renderSurface, setNativeWindow(nullptr)).Times(1);
EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1);
- EXPECT_CALL(*renderSurface, setNativeWindow(nativeWindow)).Times(1);
// --------------------------------------------------------------------
// Invocation
diff --git a/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h b/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h
index 561fd58..4950a4b 100644
--- a/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h
+++ b/services/surfaceflinger/tests/unittests/mock/system/window/MockNativeWindow.h
@@ -36,6 +36,7 @@
MOCK_METHOD1(queueBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
MOCK_CONST_METHOD2(query, int(int, int*));
MOCK_METHOD1(perform, int(int));
+ MOCK_METHOD2(perform, int(int, int));
MOCK_METHOD1(cancelBuffer_DEPRECATED, int(struct ANativeWindowBuffer*));
MOCK_METHOD2(dequeueBuffer, int(struct ANativeWindowBuffer**, int*));
MOCK_METHOD2(queueBuffer, int(struct ANativeWindowBuffer*, int));
diff --git a/services/vr/performanced/Android.bp b/services/vr/performanced/Android.bp
new file mode 100644
index 0000000..20301f6
--- /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 a548ef0..0000000
--- 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/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 8f76606..e4c50d5 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
// API version (major.minor.patch)
define VERSION_MAJOR 1
define VERSION_MINOR 1
-define VERSION_PATCH 91
+define VERSION_PATCH 93
// API limits
define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -615,6 +615,10 @@
@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"
@@ -623,6 +627,10 @@
@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 //
/////////////
@@ -1848,10 +1856,16 @@
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,
+ 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 {
@@ -2382,6 +2396,7 @@
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,
}
/////////////////
@@ -7656,6 +7671,20 @@
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 //
diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h
index 4cd8ed5..35c0664 100644
--- a/vulkan/include/vulkan/vulkan_core.h
+++ b/vulkan/include/vulkan/vulkan_core.h
@@ -43,7 +43,7 @@
#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 91
+#define VK_HEADER_VERSION 93
#define VK_NULL_HANDLE 0
@@ -454,6 +454,8 @@
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,
@@ -6101,9 +6103,10 @@
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;
@@ -7791,8 +7794,6 @@
#define VK_EXT_image_drm_format_modifier 1
-#define VK_EXT_EXTENSION_159_SPEC_VERSION 0
-#define VK_EXT_EXTENSION_159_EXTENSION_NAME "VK_EXT_extension_159"
#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"
@@ -8806,6 +8807,18 @@
+#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"
@@ -8816,6 +8829,18 @@
#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