Merge changes Iaa0846b8,Id9420941
* changes:
Remove extra isCurrent calls.
Move image creation out of latchBuffer().
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 5acc09d..e185cbe 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -57,10 +57,21 @@
export_aidl_headers: true,
},
srcs: [
- "binder/android/os/IDumpstate.aidl",
+ "binder/android/os/DumpstateOptions.cpp",
+ ":dumpstate_aidl",
+ ],
+ export_include_dirs: ["binder"],
+}
+
+filegroup {
+ name: "dumpstate_aidl",
+ srcs: [
"binder/android/os/IDumpstateListener.aidl",
"binder/android/os/IDumpstateToken.aidl",
+ //"binder/android/os/DumpstateOptions.aidl",
+ "binder/android/os/IDumpstate.aidl",
],
+ path: "binder",
}
cc_defaults {
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 49a78e7..260ea4b 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -77,6 +77,13 @@
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.
+ *returned_id = -1;
+ return binder::Status::ok();
+}
+
status_t DumpstateService::dump(int fd, const Vector<String16>&) {
dprintf(fd, "id: %d\n", ds_.id_);
dprintf(fd, "pid: %d\n", ds_.pid_);
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 7bca24a..131aff3 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -41,6 +41,9 @@
bool getSectionDetails,
sp<IDumpstateToken>* returned_token) override;
+ binder::Status startBugreport(int fd, const sp<IDumpstateListener>& listener,
+ const DumpstateOptions& options, int32_t* returned_id) override;
+
private:
Dumpstate& ds_;
std::mutex lock_;
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.aidl b/cmds/dumpstate/binder/android/os/DumpstateOptions.aidl
new file mode 100644
index 0000000..c1a7f15
--- /dev/null
+++ b/cmds/dumpstate/binder/android/os/DumpstateOptions.aidl
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+
+package android.os;
+
+/**
+ * Specifies arguments for IDumpstate.
+ * {@hide}
+ */
+parcelable DumpstateOptions cpp_header "android/os/DumpstateOptions.h";
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.cpp b/cmds/dumpstate/binder/android/os/DumpstateOptions.cpp
new file mode 100644
index 0000000..5654190
--- /dev/null
+++ b/cmds/dumpstate/binder/android/os/DumpstateOptions.cpp
@@ -0,0 +1,46 @@
+/**
+ * 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 <android/os/DumpstateOptions.h>
+
+#include <binder/IBinder.h>
+#include <binder/Parcel.h>
+
+namespace android {
+namespace os {
+
+status_t DumpstateOptions::readFromParcel(const ::android::Parcel* parcel) {
+ if (status_t err = parcel->readBool(&get_section_details)) {
+ return err;
+ }
+ if (status_t err = parcel->readUtf8FromUtf16(&name)) {
+ return err;
+ }
+ return android::OK;
+}
+
+status_t DumpstateOptions::writeToParcel(::android::Parcel* parcel) const {
+ if (status_t err = parcel->writeBool(get_section_details)) {
+ return err;
+ }
+ if (status_t err = parcel->writeUtf8AsUtf16(name)) {
+ return err;
+ }
+ return android::OK;
+}
+
+} // namespace os
+} // namespace android
diff --git a/cmds/dumpstate/binder/android/os/DumpstateOptions.h b/cmds/dumpstate/binder/android/os/DumpstateOptions.h
new file mode 100644
index 0000000..a748e3c
--- /dev/null
+++ b/cmds/dumpstate/binder/android/os/DumpstateOptions.h
@@ -0,0 +1,39 @@
+/**
+ * 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_OS_DUMPSTATE_OPTIONS_H_
+#define ANDROID_OS_DUMPSTATE_OPTIONS_H_
+
+#include <binder/Parcelable.h>
+
+namespace android {
+namespace os {
+
+struct DumpstateOptions : public android::Parcelable {
+ // If true the caller can get callbacks with per-section progress details.
+ bool get_section_details = false;
+
+ // Name of the caller.
+ std::string name;
+
+ status_t writeToParcel(android::Parcel* parcel) const override;
+ status_t readFromParcel(const android::Parcel* parcel) override;
+};
+
+} // namespace os
+} // namespace android
+
+#endif // ANDROID_OS_DUMPSTATE_OPTIONS_H_
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 9b11b96..68a4f21 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -18,6 +18,7 @@
import android.os.IDumpstateListener;
import android.os.IDumpstateToken;
+import android.os.DumpstateOptions;
/**
* Binder interface for the currently running dumpstate process.
@@ -25,6 +26,8 @@
*/
interface IDumpstate {
+
+ // TODO: remove method once startBugReport is used by Shell.
/*
* Sets the listener for this dumpstate progress.
*
@@ -35,4 +38,11 @@
*/
IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener,
boolean getSectionDetails);
+
+ /*
+ * Starts a bugreport in a child process.
+ *
+ * Returns an identifier of the bugreport process running in the background.
+ */
+ int startBugreport(int fd, IDumpstateListener listener, in DumpstateOptions options);
}
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 73098f8..28c7658 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -361,12 +361,11 @@
}
std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
- if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
- return PatchoatBootImage(isa_path, isa);
- } else {
+ if (access(preopted_boot_art_path.c_str(), F_OK) != 0) {
// No preopted boot image. Try to compile.
return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
}
+ return true;
}
static bool CreatePath(const std::string& path) {
@@ -431,29 +430,6 @@
CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory.";
}
- bool PatchoatBootImage(const std::string& output_dir, const char* isa) const {
- // This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
-
- std::vector<std::string> cmd;
- cmd.push_back("/system/bin/patchoat");
-
- cmd.push_back("--input-image-location=/system/framework/boot.art");
- cmd.push_back(StringPrintf("--output-image-directory=%s", output_dir.c_str()));
-
- cmd.push_back(StringPrintf("--instruction-set=%s", isa));
-
- int32_t base_offset = ChooseRelocationOffsetDelta(art::GetImageMinBaseAddressDelta(),
- art::GetImageMaxBaseAddressDelta());
- cmd.push_back(StringPrintf("--base-offset-delta=%d", base_offset));
-
- std::string error_msg;
- bool result = Exec(cmd, &error_msg);
- if (!result) {
- LOG(ERROR) << "Could not generate boot image: " << error_msg;
- }
- return result;
- }
-
bool Dex2oatBootImage(const std::string& boot_cp,
const std::string& art_path,
const std::string& oat_path,
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index 0f336dd..0de3bb7 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -17,11 +17,37 @@
#ifndef _LIBINPUT_DISPLAY_VIEWPORT_H
#define _LIBINPUT_DISPLAY_VIEWPORT_H
+#include <android-base/stringprintf.h>
#include <ui/DisplayInfo.h>
#include <input/Input.h>
+using android::base::StringPrintf;
+
namespace android {
+/**
+ * Describes the different type of viewports supported by input flinger.
+ * Keep in sync with values in InputManagerService.java.
+ */
+enum class ViewportType : int32_t {
+ VIEWPORT_INTERNAL = 1,
+ VIEWPORT_EXTERNAL = 2,
+ VIEWPORT_VIRTUAL = 3,
+};
+
+static const char* viewportTypeToString(ViewportType type) {
+ switch(type) {
+ case ViewportType::VIEWPORT_INTERNAL:
+ return "INTERNAL";
+ case ViewportType::VIEWPORT_EXTERNAL:
+ return "EXTERNAL";
+ case ViewportType::VIEWPORT_VIRTUAL:
+ return "VIRTUAL";
+ default:
+ return "UNKNOWN";
+ }
+}
+
/*
* Describes how coordinates are mapped on a physical display.
* See com.android.server.display.DisplayViewport.
@@ -40,12 +66,13 @@
int32_t deviceWidth;
int32_t deviceHeight;
std::string uniqueId;
+ ViewportType type;
DisplayViewport() :
displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0),
logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0),
physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0),
- deviceWidth(0), deviceHeight(0), uniqueId() {
+ deviceWidth(0), deviceHeight(0), uniqueId(), type(ViewportType::VIEWPORT_INTERNAL) {
}
bool operator==(const DisplayViewport& other) const {
@@ -61,7 +88,8 @@
&& physicalBottom == other.physicalBottom
&& deviceWidth == other.deviceWidth
&& deviceHeight == other.deviceHeight
- && uniqueId == other.uniqueId;
+ && uniqueId == other.uniqueId
+ && type == other.type;
}
bool operator!=(const DisplayViewport& other) const {
@@ -86,17 +114,22 @@
deviceWidth = width;
deviceHeight = height;
uniqueId.clear();
+ type = ViewportType::VIEWPORT_INTERNAL;
}
-};
-/**
- * Describes the different type of viewports supported by input flinger.
- * Keep in sync with values in InputManagerService.java.
- */
-enum class ViewportType : int32_t {
- VIEWPORT_INTERNAL = 1,
- VIEWPORT_EXTERNAL = 2,
- VIEWPORT_VIRTUAL = 3,
+ std::string toString() const {
+ return StringPrintf("Viewport %s: displayId=%d, orientation=%d, "
+ "logicalFrame=[%d, %d, %d, %d], "
+ "physicalFrame=[%d, %d, %d, %d], "
+ "deviceSize=[%d, %d]",
+ viewportTypeToString(type),
+ displayId, orientation,
+ logicalLeft, logicalTop,
+ logicalRight, logicalBottom,
+ physicalLeft, physicalTop,
+ physicalRight, physicalBottom,
+ deviceWidth, deviceHeight);
+ }
};
} // namespace android
diff --git a/services/inputflinger/InputApplication.h b/include/input/InputApplication.h
similarity index 100%
rename from services/inputflinger/InputApplication.h
rename to include/input/InputApplication.h
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 5fd86b4..4782c9b 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -37,6 +37,7 @@
#include <utils/BitSet.h>
namespace android {
+class Parcel;
/*
* Intermediate representation used to send input events and related signals.
@@ -143,6 +144,7 @@
virtual ~InputChannel();
public:
+ InputChannel() = default;
InputChannel(const std::string& name, int fd);
/* Creates a pair of input channels.
@@ -183,9 +185,14 @@
/* Returns a new object that has a duplicate of this channel's fd. */
sp<InputChannel> dup() const;
+ status_t write(Parcel& out) const;
+ status_t read(const Parcel& from);
+
private:
+ void setFd(int fd);
+
std::string mName;
- int mFd;
+ int mFd = -1;
};
/*
diff --git a/services/inputflinger/InputWindow.h b/include/input/InputWindow.h
similarity index 97%
rename from services/inputflinger/InputWindow.h
rename to include/input/InputWindow.h
index c481853..7c284dd 100644
--- a/services/inputflinger/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -27,7 +27,7 @@
#include "InputApplication.h"
namespace android {
-
+class Parcel;
/*
* Describes the properties of a window that can receive input.
@@ -151,6 +151,9 @@
bool supportsSplitTouch() const;
bool overlaps(const InputWindowInfo* other) const;
+
+ status_t write(Parcel& output) const;
+ static InputWindowInfo read(const Parcel& from);
};
@@ -168,9 +171,7 @@
return mInfo;
}
- inline sp<InputChannel> getInputChannel() const {
- return mInfo ? mInfo->inputChannel : nullptr;
- }
+ sp<InputChannel> getInputChannel() const;
inline std::string getName() const {
return mInfo ? mInfo->name : "<invalid>";
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b2a304a..aedf6b0 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -120,6 +120,7 @@
"liblog",
"libcutils",
"libutils",
+ "libbinderthreadstate",
],
header_libs: [
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index b2217b5..f052bcb 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "IPCThreadState"
#include <binder/IPCThreadState.h>
+#include <binderthreadstate/IPCThreadStateBase.h>
#include <binder/Binder.h>
#include <binder/BpBinder.h>
@@ -742,6 +743,7 @@
clearCaller();
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
+ mIPCThreadStateBase = IPCThreadStateBase::self();
}
IPCThreadState::~IPCThreadState()
@@ -1082,6 +1084,9 @@
"Not enough command data for brTRANSACTION");
if (result != NO_ERROR) break;
+ //Record the fact that we're in a binder call.
+ mIPCThreadStateBase->pushCurrentState(
+ IPCThreadStateBase::CallState::BINDER);
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
@@ -1129,6 +1134,7 @@
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
+ mIPCThreadStateBase->popCurrentState();
//ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n",
// mCallingPid, origPid, origUid);
@@ -1192,6 +1198,10 @@
return result;
}
+bool IPCThreadState::isServingCall() const {
+ return mIPCThreadStateBase->getCurrentBinderCallState() == IPCThreadStateBase::CallState::BINDER;
+}
+
void IPCThreadState::threadDestructor(void *st)
{
IPCThreadState* const self = static_cast<IPCThreadState*>(st);
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index e318a7f..a3f8755 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -24,11 +24,17 @@
}
Status Status::fromExceptionCode(int32_t exceptionCode) {
+ if (exceptionCode == EX_TRANSACTION_FAILED) {
+ return Status(exceptionCode, FAILED_TRANSACTION);
+ }
return Status(exceptionCode, OK);
}
Status Status::fromExceptionCode(int32_t exceptionCode,
const String8& message) {
+ if (exceptionCode == EX_TRANSACTION_FAILED) {
+ return Status(exceptionCode, FAILED_TRANSACTION, message);
+ }
return Status(exceptionCode, OK, message);
}
@@ -136,7 +142,7 @@
// Something really bad has happened, and we're not going to even
// try returning rich error data.
if (mException == EX_TRANSACTION_FAILED) {
- return mErrorCode == OK ? FAILED_TRANSACTION : mErrorCode;
+ return mErrorCode;
}
status_t status = parcel->writeInt32(mException);
@@ -158,7 +164,7 @@
void Status::setException(int32_t ex, const String8& message) {
mException = ex;
- mErrorCode = NO_ERROR; // an exception, not a transaction failure.
+ mErrorCode = ex == EX_TRANSACTION_FAILED ? FAILED_TRANSACTION : NO_ERROR;
mMessage.setTo(message);
}
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index dce3f38..40b51ad 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -29,6 +29,8 @@
// ---------------------------------------------------------------------------
namespace android {
+class IPCThreadStateBase;
+
class IPCThreadState
{
public:
@@ -89,6 +91,33 @@
// the maximum number of binder threads threads allowed for this process.
void blockUntilThreadAvailable();
+
+ // Is this thread currently serving a binder call. This method
+ // returns true if while traversing backwards from the function call
+ // stack for this thread, we encounter a function serving a binder
+ // call before encountering a hwbinder call / hitting the end of the
+ // call stack.
+ // Eg: If thread T1 went through the following call pattern
+ // 1) T1 receives and executes hwbinder call H1.
+ // 2) While handling H1, T1 makes binder call B1.
+ // 3) The handler of B1, calls into T1 with a callback B2.
+ // If isServingCall() is called during H1 before 3), this method
+ // will return false, else true.
+ //
+ // ----
+ // | B2 | ---> While callback B2 is being handled, during 3).
+ // ----
+ // | H1 | ---> While H1 is being handled.
+ // ----
+ // Fig: Thread Call stack while handling B2
+ //
+ // This is since after 3), while traversing the thread call stack,
+ // we hit a binder call before a hwbinder call / end of stack. This
+ // method may be typically used to determine whether to use
+ // hardware::IPCThreadState methods or IPCThreadState methods to
+ // infer information about thread state.
+ bool isServingCall() const;
+
private:
IPCThreadState();
~IPCThreadState();
@@ -128,6 +157,7 @@
uid_t mCallingUid;
int32_t mStrictModePolicy;
int32_t mLastTransactionBinderFlags;
+ IPCThreadStateBase *mIPCThreadStateBase;
};
}; // namespace android
diff --git a/libs/binder/include/binder/ParcelFileDescriptor.h b/libs/binder/include/binder/ParcelFileDescriptor.h
index 455462b..ad950af 100644
--- a/libs/binder/include/binder/ParcelFileDescriptor.h
+++ b/libs/binder/include/binder/ParcelFileDescriptor.h
@@ -31,6 +31,7 @@
public:
ParcelFileDescriptor();
explicit ParcelFileDescriptor(android::base::unique_fd fd);
+ explicit ParcelFileDescriptor(ParcelFileDescriptor&& other) : mFd(std::move(other.mFd)) { }
~ParcelFileDescriptor() override;
int get() const { return mFd.get(); }
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
new file mode 100644
index 0000000..cc0a29d
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_auto_utils.h
+ * @brief These objects provide a more C++-like thin interface to the .
+ */
+
+#pragma once
+
+#include <android/binder_ibinder.h>
+#include <android/binder_parcel.h>
+#include <android/binder_status.h>
+
+#include <assert.h>
+
+#ifdef __cplusplus
+
+#include <cstddef>
+
+namespace ndk {
+
+/**
+ * Represents one strong pointer to an AIBinder object.
+ */
+class SpAIBinder {
+public:
+ /**
+ * Takes ownership of one strong refcount of binder.
+ */
+ explicit SpAIBinder(AIBinder* binder = nullptr) : mBinder(binder) {}
+
+ /**
+ * Convenience operator for implicitly constructing an SpAIBinder from nullptr. This is not
+ * explicit because it is not taking ownership of anything.
+ */
+ SpAIBinder(std::nullptr_t) : SpAIBinder() {}
+
+ /**
+ * This will delete the underlying object if it exists. See operator=.
+ */
+ SpAIBinder(const SpAIBinder& other) { *this = other; }
+
+ /**
+ * This deletes the underlying object if it exists. See set.
+ */
+ ~SpAIBinder() { set(nullptr); }
+
+ /**
+ * This takes ownership of a binder from another AIBinder object but it does not affect the
+ * ownership of that other object.
+ */
+ SpAIBinder& operator=(const SpAIBinder& other) {
+ AIBinder_incStrong(other.mBinder);
+ set(other.mBinder);
+ return *this;
+ }
+
+ /**
+ * Takes ownership of one strong refcount of binder
+ */
+ void set(AIBinder* binder) {
+ AIBinder* old = *const_cast<AIBinder* volatile*>(&mBinder);
+ if (old != nullptr) AIBinder_decStrong(old);
+ if (old != *const_cast<AIBinder* volatile*>(&mBinder)) {
+ __assert(__FILE__, __LINE__, "Race detected.");
+ }
+ mBinder = binder;
+ }
+
+ /**
+ * This returns the underlying binder object for transactions. If it is used to create another
+ * SpAIBinder object, it should first be incremented.
+ */
+ AIBinder* get() const { return mBinder; }
+
+ /**
+ * This allows the value in this class to be set from beneath it. If you call this method and
+ * then change the value of T*, you must take ownership of the value you are replacing and add
+ * ownership to the object that is put in here.
+ *
+ * Recommended use is like this:
+ * SpAIBinder a; // will be nullptr
+ * SomeInitFunction(a.getR()); // value is initialized with refcount
+ *
+ * Other usecases are discouraged.
+ *
+ */
+ AIBinder** getR() { return &mBinder; }
+
+private:
+ AIBinder* mBinder = nullptr;
+};
+
+/**
+ * This baseclass owns a single object, used to make various classes RAII.
+ */
+template <typename T, void (*Destroy)(T*)>
+class ScopedAResource {
+public:
+ /**
+ * Takes ownership of t.
+ */
+ explicit ScopedAResource(T* t = nullptr) : mT(t) {}
+
+ /**
+ * This deletes the underlying object if it exists. See set.
+ */
+ ~ScopedAResource() { set(nullptr); }
+
+ /**
+ * Takes ownership of t.
+ */
+ void set(T* t) {
+ Destroy(mT);
+ mT = t;
+ }
+
+ /**
+ * This returns the underlying object to be modified but does not affect ownership.
+ */
+ T* get() { return mT; }
+
+ /**
+ * This returns the const underlying object but does not affect ownership.
+ */
+ const T* get() const { return mT; }
+
+ /**
+ * This allows the value in this class to be set from beneath it. If you call this method and
+ * then change the value of T*, you must take ownership of the value you are replacing and add
+ * ownership to the object that is put in here.
+ *
+ * Recommended use is like this:
+ * ScopedAResource<T> a; // will be nullptr
+ * SomeInitFunction(a.getR()); // value is initialized with refcount
+ *
+ * Other usecases are discouraged.
+ *
+ */
+ T** getR() { return &mT; }
+
+ // copy-constructing, or move/copy assignment is disallowed
+ ScopedAResource(const ScopedAResource&) = delete;
+ ScopedAResource& operator=(const ScopedAResource&) = delete;
+ ScopedAResource& operator=(ScopedAResource&&) = delete;
+
+ // move-constructing is okay
+ ScopedAResource(ScopedAResource&&) = default;
+
+private:
+ T* mT;
+};
+
+/**
+ * Convenience wrapper. See AParcel.
+ */
+class ScopedAParcel : public ScopedAResource<AParcel, AParcel_delete> {
+public:
+ /**
+ * Takes ownership of a.
+ */
+ explicit ScopedAParcel(AParcel* a = nullptr) : ScopedAResource(a) {}
+ ~ScopedAParcel() {}
+ ScopedAParcel(ScopedAParcel&&) = default;
+};
+
+/**
+ * Convenience wrapper. See AStatus.
+ */
+class ScopedAStatus : public ScopedAResource<AStatus, AStatus_delete> {
+public:
+ /**
+ * Takes ownership of a.
+ */
+ explicit ScopedAStatus(AStatus* a = nullptr) : ScopedAResource(a) {}
+ ~ScopedAStatus() {}
+ ScopedAStatus(ScopedAStatus&&) = default;
+
+ /**
+ * See AStatus_isOk.
+ */
+ bool isOk() { return get() != nullptr && AStatus_isOk(get()); }
+};
+
+/**
+ * Convenience wrapper. See AIBinder_DeathRecipient.
+ */
+class ScopedAIBinder_DeathRecipient
+ : public ScopedAResource<AIBinder_DeathRecipient, AIBinder_DeathRecipient_delete> {
+public:
+ /**
+ * Takes ownership of a.
+ */
+ explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr)
+ : ScopedAResource(a) {}
+ ~ScopedAIBinder_DeathRecipient() {}
+ ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default;
+};
+
+/**
+ * Convenience wrapper. See AIBinder_Weak.
+ */
+class ScopedAIBinder_Weak : public ScopedAResource<AIBinder_Weak, AIBinder_Weak_delete> {
+public:
+ /**
+ * Takes ownership of a.
+ */
+ explicit ScopedAIBinder_Weak(AIBinder_Weak* a = nullptr) : ScopedAResource(a) {}
+ ~ScopedAIBinder_Weak() {}
+ ScopedAIBinder_Weak(ScopedAIBinder_Weak&&) = default;
+
+ /**
+ * See AIBinder_Weak_promote.
+ */
+ SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
+};
+
+} // namespace ndk
+
+#endif // __cplusplus
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index f237e69..c222c16 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -207,6 +207,8 @@
* null. The exact cookie must also be used to unlink this transaction (see AIBinder_linkToDeath).
* This function may return a binder transaction failure. The cookie can be used both for
* identification and holding user data.
+ *
+ * If binder is local, this will return STATUS_INVALID_OPERATION.
*/
binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
void* cookie) __INTRODUCED_IN(29);
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
new file mode 100644
index 0000000..1a9018a
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_interface_utils.h
+ * @brief This provides common C++ classes for common operations and as base classes for C++
+ * interfaces.
+ */
+
+#pragma once
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
+
+#include <assert.h>
+
+#ifdef __cplusplus
+
+#include <memory>
+#include <mutex>
+
+namespace ndk {
+
+/**
+ * analog using std::shared_ptr for internally held refcount
+ *
+ * ref must be called at least one time during the lifetime of this object. The recommended way to construct
+ * this object is with SharedRefBase::make.
+ */
+class SharedRefBase {
+public:
+ SharedRefBase() {}
+ virtual ~SharedRefBase() {
+ std::call_once(mFlagThis, [&]() {
+ __assert(__FILE__, __LINE__, "SharedRefBase: no ref created during lifetime");
+ });
+ }
+
+ /**
+ * A shared_ptr must be held to this object when this is called. This must be called once during
+ * the lifetime of this object.
+ */
+ std::shared_ptr<SharedRefBase> ref() {
+ std::shared_ptr<SharedRefBase> thiz = mThis.lock();
+
+ std::call_once(mFlagThis, [&]() { mThis = thiz = std::shared_ptr<SharedRefBase>(this); });
+
+ return thiz;
+ }
+
+ /**
+ * Convenience method for a ref (see above) which automatically casts to the desired child type.
+ */
+ template <typename CHILD>
+ std::shared_ptr<CHILD> ref() {
+ return std::static_pointer_cast<CHILD>(ref());
+ }
+
+ /**
+ * Convenience method for making an object directly with a reference.
+ */
+ template<class T, class... Args>
+ static std::shared_ptr<T> make(Args&&... args) {
+ T* t = new T(std::forward<Args>(args)...);
+ return t->template ref<T>();
+ }
+
+private:
+ std::once_flag mFlagThis;
+ std::weak_ptr<SharedRefBase> mThis;
+};
+
+/**
+ * wrapper analog to IInterface
+ */
+class ICInterface : public SharedRefBase {
+public:
+ ICInterface() {}
+ virtual ~ICInterface() {}
+
+ /**
+ * This either returns the single existing implementation or creates a new implementation.
+ */
+ virtual SpAIBinder asBinder() = 0;
+
+ /**
+ * Returns whether this interface is in a remote process. If it cannot be determined locally,
+ * this will be checked using AIBinder_isRemote.
+ */
+ virtual bool isRemote() = 0;
+};
+
+/**
+ * implementation of IInterface for server (n = native)
+ */
+template <typename INTERFACE>
+class BnCInterface : public INTERFACE {
+public:
+ BnCInterface() {}
+ virtual ~BnCInterface() {}
+
+ SpAIBinder asBinder() override;
+
+ bool isRemote() override { return true; }
+
+protected:
+ /**
+ * This function should only be called by asBinder. Otherwise, there is a possibility of
+ * multiple AIBinder* objects being created for the same instance of an object.
+ */
+ virtual SpAIBinder createBinder() = 0;
+
+private:
+ std::mutex mMutex; // for asBinder
+ ScopedAIBinder_Weak mWeakBinder;
+};
+
+/**
+ * implementation of IInterface for client (p = proxy)
+ */
+template <typename INTERFACE>
+class BpCInterface : public INTERFACE {
+public:
+ BpCInterface(const SpAIBinder& binder) : mBinder(binder) {}
+ virtual ~BpCInterface() {}
+
+ SpAIBinder asBinder() override;
+
+ bool isRemote() override { return AIBinder_isRemote(mBinder.get()); }
+
+private:
+ SpAIBinder mBinder;
+};
+
+template <typename INTERFACE>
+SpAIBinder BnCInterface<INTERFACE>::asBinder() {
+ std::lock_guard<std::mutex> l(mMutex);
+
+ SpAIBinder binder;
+ if (mWeakBinder.get() != nullptr) {
+ binder.set(AIBinder_Weak_promote(mWeakBinder.get()));
+ }
+ if (binder.get() == nullptr) {
+ binder = createBinder();
+ mWeakBinder.set(AIBinder_Weak_new(binder.get()));
+ }
+
+ return binder;
+}
+
+template <typename INTERFACE>
+SpAIBinder BpCInterface<INTERFACE>::asBinder() {
+ return mBinder;
+}
+
+} // namespace ndk
+
+#endif // __cplusplus
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index a3800da..0e97b50 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -88,6 +88,43 @@
binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status)
__INTRODUCED_IN(29);
+/**
+ * Writes string value to the next location in a non-null parcel.
+ */
+binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length)
+ __INTRODUCED_IN(29);
+
+/**
+ * This is called to allocate a buffer
+ *
+ * The length here includes the space required to insert a '\0' for a properly formed c-str. If the
+ * buffer returned from this function is retStr, it will be filled by AParcel_readString with the
+ * data from the remote process, and it will be filled such that retStr[length] == '\0'.
+ *
+ * If allocation fails, null should be returned.
+ */
+typedef void* (*AParcel_string_reallocator)(void* stringData, size_t length);
+
+/**
+ * This is called to get the buffer from a stringData object.
+ */
+typedef char* (*AParcel_string_getter)(void* stringData);
+
+/**
+ * Reads and allocates string value from the next location in a non-null parcel.
+ *
+ * Data is passed to the string allocator once the string size is known. This data should be used to
+ * point to some kind of string data. For instance, it could be a char*, and the string allocator
+ * could be realloc. Then the getter would simply be a cast to char*. In more complicated cases,
+ * stringData could be a structure containing additional string data.
+ *
+ * If this function returns a success, the buffer returned by allocator when passed stringData will
+ * contain a null-terminated c-str read from the binder.
+ */
+binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_reallocator reallocator,
+ AParcel_string_getter getter, void** stringData)
+ __INTRODUCED_IN(29);
+
// @START
/**
* Writes int32_t value to the next location in a non-null parcel.
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
new file mode 100644
index 0000000..d3e6cae
--- /dev/null
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_parcel_utils.h
+ * @brief A collection of helper wrappers for AParcel.
+ */
+
+#pragma once
+
+#include <android/binder_parcel.h>
+
+#ifdef __cplusplus
+
+#include <string>
+
+namespace ndk {
+
+/**
+ * Takes a std::string and reallocates it to the specified length. For use with AParcel_readString.
+ * See use below in AParcel_readString.
+ */
+static inline void* AParcel_std_string_reallocator(void* stringData, size_t length) {
+ std::string* str = static_cast<std::string*>(stringData);
+ str->resize(length - 1);
+ return stringData;
+}
+
+/**
+ * Takes a std::string and returns the inner char*.
+ */
+static inline char* AParcel_std_string_getter(void* stringData) {
+ std::string* str = static_cast<std::string*>(stringData);
+ return &(*str)[0];
+}
+
+/**
+ * Convenience API for writing a std::string.
+ */
+static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) {
+ return AParcel_writeString(parcel, str.c_str(), str.size());
+}
+
+/**
+ * Convenience API for reading a std::string.
+ */
+static inline binder_status_t AParcel_readString(const AParcel* parcel, std::string* str) {
+ void* stringData = static_cast<void*>(str);
+ return AParcel_readString(parcel, AParcel_std_string_reallocator, AParcel_std_string_getter,
+ &stringData);
+}
+
+} // namespace ndk
+
+#endif // __cplusplus
+
+/** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 4f486c9..2a1bff1 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -32,6 +32,7 @@
AParcel_readInt64;
AParcel_readNullableStrongBinder;
AParcel_readStatusHeader;
+ AParcel_readString;
AParcel_readStrongBinder;
AParcel_readUint32;
AParcel_readUint64;
@@ -43,6 +44,7 @@
AParcel_writeInt32;
AParcel_writeInt64;
AParcel_writeStatusHeader;
+ AParcel_writeString;
AParcel_writeStrongBinder;
AParcel_writeUint32;
AParcel_writeUint64;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 385e898..3e03e90 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -20,7 +20,11 @@
#include "ibinder_internal.h"
#include "status_internal.h"
+#include <limits>
+
+#include <android-base/logging.h>
#include <binder/Parcel.h>
+#include <utils/Unicode.h>
using ::android::IBinder;
using ::android::Parcel;
@@ -69,6 +73,67 @@
return ret;
}
+binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) {
+ 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()) {
+ LOG(WARNING) << __func__ << ": Invalid string length: " << len16;
+ return STATUS_BAD_VALUE;
+ }
+
+ status_t err = parcel->get()->writeInt32(len16);
+ if (err) {
+ return PruneStatusT(err);
+ }
+
+ void* str16 = parcel->get()->writeInplace((len16 + 1) * sizeof(char16_t));
+ if (str16 == nullptr) {
+ return STATUS_NO_MEMORY;
+ }
+
+ utf8_to_utf16(str8, length, (char16_t*)str16, (size_t)len16 + 1);
+
+ return STATUS_OK;
+}
+
+binder_status_t AParcel_readString(const AParcel* parcel, AParcel_string_reallocator reallocator,
+ AParcel_string_getter getter, void** stringData) {
+ size_t len16;
+ const char16_t* str16 = parcel->get()->readString16Inplace(&len16);
+
+ if (str16 == nullptr) {
+ LOG(WARNING) << __func__ << ": Failed to read string in place.";
+ return STATUS_UNEXPECTED_NULL;
+ }
+
+ ssize_t len8;
+
+ if (len16 == 0) {
+ len8 = 1;
+ } else {
+ len8 = utf16_to_utf8_length(str16, len16) + 1;
+ }
+
+ if (len8 <= 0 || len8 >= std::numeric_limits<int32_t>::max()) {
+ LOG(WARNING) << __func__ << ": Invalid string length: " << len8;
+ return STATUS_BAD_VALUE;
+ }
+
+ *stringData = reallocator(*stringData, len8);
+ char* str8 = getter(*stringData);
+
+ if (str8 == nullptr) {
+ LOG(WARNING) << __func__ << ": AParcel_string_allocator failed to allocate.";
+ return STATUS_NO_MEMORY;
+ }
+
+ utf16_to_utf8(str16, len16, str8, len8);
+
+ return STATUS_OK;
+}
+
// See gen_parcel_helper.py. These auto-generated read/write methods use the same types for
// libbinder and this library.
// @START
diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp
index e0ae469..1f75b0b 100644
--- a/libs/binder/ndk/status.cpp
+++ b/libs/binder/ndk/status.cpp
@@ -27,11 +27,11 @@
}
AStatus* AStatus_fromExceptionCode(binder_exception_t exception) {
- return new AStatus(Status::fromExceptionCode(exception));
+ return new AStatus(Status::fromExceptionCode(PruneException(exception)));
}
AStatus* AStatus_fromExceptionCodeWithMessage(binder_exception_t exception, const char* message) {
- return new AStatus(Status::fromExceptionCode(exception, message));
+ return new AStatus(Status::fromExceptionCode(PruneException(exception), message));
}
AStatus* AStatus_fromServiceSpecificError(int32_t serviceSpecific) {
@@ -43,7 +43,7 @@
}
AStatus* AStatus_fromStatus(binder_status_t status) {
- return new AStatus(Status::fromStatusT(status));
+ return new AStatus(Status::fromStatusT(PruneStatusT(status)));
}
bool AStatus_isOk(const AStatus* status) {
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index 3fc096a..22bf1e5 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -131,3 +131,6 @@
EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName2));
EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
}
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
diff --git a/libs/binderthreadstate/Android.bp b/libs/binderthreadstate/Android.bp
new file mode 100644
index 0000000..7106cbb
--- /dev/null
+++ b/libs/binderthreadstate/Android.bp
@@ -0,0 +1,44 @@
+// 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.
+
+cc_library {
+ name: "libbinderthreadstate",
+ recovery_available: true,
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ srcs: [
+ "IPCThreadStateBase.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libutils",
+ ],
+
+ export_include_dirs: ["include"],
+
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/libs/binderthreadstate/IPCThreadStateBase.cpp b/libs/binderthreadstate/IPCThreadStateBase.cpp
new file mode 100644
index 0000000..fede151
--- /dev/null
+++ b/libs/binderthreadstate/IPCThreadStateBase.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "IPCThreadStateBase"
+
+#include <binderthreadstate/IPCThreadStateBase.h>
+#include <android-base/macros.h>
+
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+
+namespace android {
+
+static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gHaveTLS = false;
+static pthread_key_t gTLS = 0;
+
+IPCThreadStateBase::IPCThreadStateBase() {
+ pthread_setspecific(gTLS, this);
+}
+
+IPCThreadStateBase* IPCThreadStateBase::self()
+{
+ if (gHaveTLS) {
+restart:
+ const pthread_key_t k = gTLS;
+ IPCThreadStateBase* st = (IPCThreadStateBase*)pthread_getspecific(k);
+ if (st) return st;
+ return new IPCThreadStateBase;
+ }
+
+ pthread_mutex_lock(&gTLSMutex);
+ if (!gHaveTLS) {
+ int key_create_value = pthread_key_create(&gTLS, threadDestructor);
+ if (key_create_value != 0) {
+ pthread_mutex_unlock(&gTLSMutex);
+ ALOGW("IPCThreadStateBase::self() unable to create TLS key, expect a crash: %s\n",
+ strerror(key_create_value));
+ return nullptr;
+ }
+ gHaveTLS = true;
+ }
+ pthread_mutex_unlock(&gTLSMutex);
+ goto restart;
+}
+
+void IPCThreadStateBase::pushCurrentState(CallState callState) {
+ mCallStateStack.emplace(callState);
+}
+
+IPCThreadStateBase::CallState IPCThreadStateBase::popCurrentState() {
+ ALOG_ASSERT(mCallStateStack.size > 0);
+ CallState val = mCallStateStack.top();
+ mCallStateStack.pop();
+ return val;
+}
+
+IPCThreadStateBase::CallState IPCThreadStateBase::getCurrentBinderCallState() {
+ if (mCallStateStack.size() > 0) {
+ return mCallStateStack.top();
+ }
+ return CallState::NONE;
+}
+
+void IPCThreadStateBase::threadDestructor(void *st)
+{
+ IPCThreadStateBase* const self = static_cast<IPCThreadStateBase*>(st);
+ if (self) {
+ delete self;
+ }
+}
+
+}; // namespace android
diff --git a/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h b/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h
new file mode 100644
index 0000000..6fdcc84
--- /dev/null
+++ b/libs/binderthreadstate/include/binderthreadstate/IPCThreadStateBase.h
@@ -0,0 +1,44 @@
+/*
+ * 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 BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
+#define BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
+
+#include <stack>
+namespace android {
+
+class IPCThreadStateBase {
+public:
+ enum CallState {
+ HWBINDER,
+ BINDER,
+ NONE,
+ };
+ static IPCThreadStateBase* self();
+ void pushCurrentState(CallState callState);
+ CallState popCurrentState();
+ CallState getCurrentBinderCallState();
+
+private:
+ IPCThreadStateBase();
+ static void threadDestructor(void *st);
+
+ std::stack<CallState> mCallStateStack;
+};
+
+}; // namespace android
+
+#endif // BINDER_THREADSTATE_IPC_THREADSTATE_BASE_H
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index 06d597c..3dac037 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -18,8 +18,8 @@
#include <gui/BufferHubProducer.h>
#include <inttypes.h>
#include <log/log.h>
-#include <private/dvr/detached_buffer.h>
#include <system/window.h>
+#include <ui/BufferHubBuffer.h>
#include <ui/DetachedBufferHandle.h>
namespace android {
@@ -400,14 +400,14 @@
ALOGE("attachBuffer: DetachedBufferHandle cannot be NULL.");
return BAD_VALUE;
}
- auto detached_buffer = DetachedBuffer::Import(std::move(detached_handle->handle()));
+ auto detached_buffer = BufferHubBuffer::Import(std::move(detached_handle->handle()));
if (detached_buffer == nullptr) {
- ALOGE("attachBuffer: DetachedBuffer cannot be NULL.");
+ ALOGE("attachBuffer: BufferHubBuffer cannot be NULL.");
return BAD_VALUE;
}
auto status_or_handle = detached_buffer->Promote();
if (!status_or_handle.ok()) {
- ALOGE("attachBuffer: Failed to promote a DetachedBuffer into a BufferProducer, error=%d.",
+ ALOGE("attachBuffer: Failed to promote a BufferHubBuffer into a BufferProducer, error=%d.",
status_or_handle.error());
return BAD_VALUE;
}
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index a379ad6..85ae433 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -621,7 +621,7 @@
// ============================================================================
FrameEventHistoryDelta& FrameEventHistoryDelta::operator=(
- FrameEventHistoryDelta&& src) {
+ FrameEventHistoryDelta&& src) noexcept {
mCompositorTiming = src.mCompositorTiming;
if (CC_UNLIKELY(!mDeltas.empty())) {
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index 9716be4..e06e40f 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -311,7 +311,7 @@
// Movable.
FrameEventHistoryDelta(FrameEventHistoryDelta&& src) = default;
- FrameEventHistoryDelta& operator=(FrameEventHistoryDelta&& src);
+ FrameEventHistoryDelta& operator=(FrameEventHistoryDelta&& src) noexcept;
// Not copyable.
FrameEventHistoryDelta(const FrameEventHistoryDelta& src) = delete;
FrameEventHistoryDelta& operator=(
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 02064c6..7ecadf8 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -44,6 +44,7 @@
"libgui",
"libhidlbase",
"libhidltransport",
+ "libinput",
"libui",
"libutils",
"libnativewindow"
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index a2d6a8a..72558a6 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -47,11 +47,14 @@
"InputTransport.cpp",
"VelocityControl.cpp",
"VelocityTracker.cpp",
+ "InputApplication.cpp",
+ "InputWindow.cpp"
],
shared_libs: [
"libutils",
"libbinder",
+ "libui"
],
sanitize: {
diff --git a/services/inputflinger/InputApplication.cpp b/libs/input/InputApplication.cpp
similarity index 96%
rename from services/inputflinger/InputApplication.cpp
rename to libs/input/InputApplication.cpp
index c56dfe6..a0d1668 100644
--- a/services/inputflinger/InputApplication.cpp
+++ b/libs/input/InputApplication.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "InputApplication"
-#include "InputApplication.h"
+#include <input/InputApplication.h>
#include <android/log.h>
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 770d483..32444f9 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -30,6 +30,7 @@
#include <cutils/properties.h>
#include <log/log.h>
+#include <binder/Parcel.h>
#include <input/InputTransport.h>
namespace android {
@@ -100,15 +101,13 @@
// --- InputChannel ---
InputChannel::InputChannel(const std::string& name, int fd) :
- mName(name), mFd(fd) {
+ mName(name) {
#if DEBUG_CHANNEL_LIFECYCLE
ALOGD("Input channel constructed: name='%s', fd=%d",
mName.c_str(), fd);
#endif
- int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
- LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
- "non-blocking. errno=%d", mName.c_str(), errno);
+ setFd(fd);
}
InputChannel::~InputChannel() {
@@ -120,6 +119,18 @@
::close(mFd);
}
+void InputChannel::setFd(int fd) {
+ if (mFd > 0) {
+ ::close(mFd);
+ }
+ mFd = fd;
+ if (mFd > 0) {
+ int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
+ LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
+ "non-blocking. errno=%d", mName.c_str(), errno);
+ }
+}
+
status_t InputChannel::openInputChannelPair(const std::string& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
int sockets[2];
@@ -230,6 +241,31 @@
}
+status_t InputChannel::write(Parcel& out) const {
+ status_t s = out.writeString8(String8(getName().c_str()));
+
+ if (s != OK) {
+ return s;
+ }
+
+ s = out.writeDupFileDescriptor(getFd());
+
+ return s;
+}
+
+status_t InputChannel::read(const Parcel& from) {
+ mName = from.readString8();
+
+ int rawFd = from.readFileDescriptor();
+ setFd(::dup(rawFd));
+
+ if (mFd < 0) {
+ return BAD_VALUE;
+ }
+
+ return OK;
+}
+
// --- InputPublisher ---
InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
new file mode 100644
index 0000000..f94faba
--- /dev/null
+++ b/libs/input/InputWindow.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "InputWindow"
+#define LOG_NDEBUG 0
+
+#include <binder/Parcel.h>
+#include <input/InputWindow.h>
+#include <input/InputTransport.h>
+
+#include <log/log.h>
+
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+namespace android {
+
+// --- InputWindowInfo ---
+void InputWindowInfo::addTouchableRegion(const Rect& region) {
+ touchableRegion.orSelf(region);
+}
+
+bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
+ return touchableRegion.contains(x,y);
+}
+
+bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
+ return x >= frameLeft && x < frameRight
+ && y >= frameTop && y < frameBottom;
+}
+
+bool InputWindowInfo::isTrustedOverlay() const {
+ return layoutParamsType == TYPE_INPUT_METHOD
+ || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
+ || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
+ || layoutParamsType == TYPE_STATUS_BAR
+ || layoutParamsType == TYPE_NAVIGATION_BAR
+ || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
+ || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
+ || layoutParamsType == TYPE_DOCK_DIVIDER
+ || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY
+ || layoutParamsType == TYPE_INPUT_CONSUMER;
+}
+
+bool InputWindowInfo::supportsSplitTouch() const {
+ return layoutParamsFlags & FLAG_SPLIT_TOUCH;
+}
+
+bool InputWindowInfo::overlaps(const InputWindowInfo* other) const {
+ return frameLeft < other->frameRight && frameRight > other->frameLeft
+ && frameTop < other->frameBottom && frameBottom > other->frameTop;
+}
+
+status_t InputWindowInfo::write(Parcel& output) const {
+ if (inputChannel == nullptr) {
+ output.writeInt32(0);
+ return OK;
+ }
+ output.writeInt32(1);
+ status_t s = inputChannel->write(output);
+ if (s != OK) return s;
+
+ output.writeString8(String8(name.c_str()));
+ output.writeInt32(layoutParamsFlags);
+ output.writeInt32(layoutParamsType);
+ output.writeInt64(dispatchingTimeout);
+ output.writeInt32(frameLeft);
+ output.writeInt32(frameTop);
+ output.writeInt32(frameRight);
+ output.writeInt32(frameBottom);
+ output.writeFloat(scaleFactor);
+ output.writeBool(visible);
+ output.writeBool(canReceiveKeys);
+ output.writeBool(hasFocus);
+ output.writeBool(hasWallpaper);
+ output.writeBool(paused);
+ output.writeInt32(layer);
+ output.writeInt32(ownerPid);
+ output.writeInt32(ownerUid);
+ output.writeInt32(inputFeatures);
+ output.writeInt32(displayId);
+ output.write(touchableRegion);
+
+ return OK;
+}
+
+InputWindowInfo InputWindowInfo::read(const Parcel& from) {
+ InputWindowInfo ret;
+
+ if (from.readInt32() == 0) {
+ return ret;
+
+ }
+ sp<InputChannel> inputChannel = new InputChannel();
+ status_t s = inputChannel->read(from);
+ if (s != OK) {
+ return ret;
+ }
+
+ ret.inputChannel = inputChannel;
+ ret.name = from.readString8().c_str();
+ ret.layoutParamsFlags = from.readInt32();
+ ret.layoutParamsType = from.readInt32();
+ ret.dispatchingTimeout = from.readInt64();
+ ret.frameLeft = from.readInt32();
+ ret.frameTop = from.readInt32();
+ ret.frameRight = from.readInt32();
+ ret.frameBottom = from.readInt32();
+ ret.scaleFactor = from.readFloat();
+ ret.visible = from.readBool();
+ ret.canReceiveKeys = from.readBool();
+ ret.hasFocus = from.readBool();
+ ret.hasWallpaper = from.readBool();
+ ret.paused = from.readBool();
+ ret.layer = from.readInt32();
+ ret.ownerPid = from.readInt32();
+ ret.ownerUid = from.readInt32();
+ ret.inputFeatures = from.readInt32();
+ ret.displayId = from.readInt32();
+ from.read(ret.touchableRegion);
+
+ return ret;
+}
+
+// --- InputWindowHandle ---
+
+InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
+ inputApplicationHandle(inputApplicationHandle), mInfo(nullptr) {
+}
+
+InputWindowHandle::~InputWindowHandle() {
+ delete mInfo;
+}
+
+void InputWindowHandle::releaseInfo() {
+ if (mInfo) {
+ delete mInfo;
+ mInfo = nullptr;
+ }
+}
+
+sp<InputChannel> InputWindowHandle::getInputChannel() const {
+ return mInfo ? mInfo->inputChannel : nullptr;
+}
+
+} // namespace android
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index f06119f..fdd945e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -6,6 +6,7 @@
"InputEvent_test.cpp",
"InputPublisherAndConsumer_test.cpp",
"VelocityTracker_test.cpp",
+ "InputWindow_test.cpp"
],
cflags: [
"-Wall",
@@ -34,4 +35,12 @@
"-Wall",
"-Werror",
],
+ shared_libs: [
+ "libinput",
+ "libcutils",
+ "libutils",
+ "libbinder",
+ "libui",
+ "libbase",
+ ]
}
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp
new file mode 100644
index 0000000..39ad26e
--- /dev/null
+++ b/libs/input/tests/InputWindow_test.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+
+#include <input/InputWindow.h>
+#include <input/InputTransport.h>
+
+namespace android {
+namespace test {
+
+TEST(InputWindowInfo, ParcellingWithoutChannel) {
+ InputWindowInfo i;
+ i.inputChannel = nullptr;
+
+ Parcel p;
+ ASSERT_EQ(OK, i.write(p));
+ p.setDataPosition(0);
+ InputWindowInfo i2 = InputWindowInfo::read(p);
+ ASSERT_TRUE(i2.inputChannel == nullptr);
+}
+
+TEST(InputWindowInfo, Parcelling) {
+ sp<InputChannel> channel, junkChannel;
+ status_t result = InputChannel::openInputChannelPair("name", channel, junkChannel);
+ ASSERT_EQ(OK, result) << "openInputChannelPair should have returned valid channels";
+
+ InputWindowInfo i;
+ i.inputChannel = channel;
+ i.name = "Foobar";
+ i.layoutParamsFlags = 7;
+ i.layoutParamsType = 39;
+ i.dispatchingTimeout = 12;
+ i.frameLeft = 93;
+ i.frameTop = 34;
+ i.frameRight = 16;
+ i.frameBottom = 19;
+ i.scaleFactor = 0.3;
+ i.visible = false;
+ i.canReceiveKeys = false;
+ i.hasFocus = false;
+ i.hasWallpaper = false;
+ i.paused = false;
+ i.layer = 7;
+ i.ownerPid = 19;
+ i.ownerUid = 24;
+ i.inputFeatures = 29;
+ i.displayId = 34;
+
+ Parcel p;
+ i.write(p);
+
+ p.setDataPosition(0);
+ InputWindowInfo i2 = InputWindowInfo::read(p);
+ ASSERT_EQ(i.inputChannel->getName(), i2.inputChannel->getName());
+ ASSERT_EQ(i.name, i2.name);
+ ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags);
+ ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType);
+ ASSERT_EQ(i.dispatchingTimeout, i2.dispatchingTimeout);
+ ASSERT_EQ(i.frameLeft, i2.frameLeft);
+ ASSERT_EQ(i.frameTop, i2.frameTop);
+ ASSERT_EQ(i.frameRight, i2.frameRight);
+ ASSERT_EQ(i.frameBottom, i2.frameBottom);
+ ASSERT_EQ(i.scaleFactor, i2.scaleFactor);
+ ASSERT_EQ(i.visible, i2.visible);
+ ASSERT_EQ(i.canReceiveKeys, i2.canReceiveKeys);
+ ASSERT_EQ(i.hasFocus, i2.hasFocus);
+ ASSERT_EQ(i.hasWallpaper, i2.hasWallpaper);
+ ASSERT_EQ(i.paused, i2.paused);
+ ASSERT_EQ(i.layer, i2.layer);
+ ASSERT_EQ(i.ownerPid, i2.ownerPid);
+ ASSERT_EQ(i.ownerUid, i2.ownerUid);
+ ASSERT_EQ(i.inputFeatures, i2.inputFeatures);
+ ASSERT_EQ(i.displayId, i2.displayId);
+}
+
+} // namespace test
+} // namespace android
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 5242a18..af97c34 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "VelocityTracker_test"
+#include <array>
#include <math.h>
#include <android-base/stringprintf.h>
@@ -34,29 +35,35 @@
// here EV = expected value, tol = VELOCITY_TOLERANCE
constexpr float VELOCITY_TOLERANCE = 0.2;
+// estimate coefficients must be within 0.001% of the target value
+constexpr float COEFFICIENT_TOLERANCE = 0.00001;
+
// --- VelocityTrackerTest ---
class VelocityTrackerTest : public testing::Test { };
-static void checkVelocity(float Vactual, float Vtarget) {
- // Compare directions
- if ((Vactual > 0 && Vtarget <= 0) || (Vactual < 0 && Vtarget >= 0)) {
- FAIL() << StringPrintf("Velocity %f does not have the same direction"
- " as the target velocity %f", Vactual, Vtarget);
- }
+/*
+ * Similar to EXPECT_NEAR, but ensures that the difference between the two float values
+ * is at most a certain fraction of the target value.
+ * If fraction is zero, require exact match.
+ */
+static void EXPECT_NEAR_BY_FRACTION(float actual, float target, float fraction) {
+ float tolerance = fabsf(target * fraction);
- // Compare magnitudes
- const float Vlower = fabsf(Vtarget * (1 - VELOCITY_TOLERANCE));
- const float Vupper = fabsf(Vtarget * (1 + VELOCITY_TOLERANCE));
- if (fabsf(Vactual) < Vlower) {
- FAIL() << StringPrintf("Velocity %f is more than %.0f%% below target velocity %f",
- Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+ if (target == 0 && fraction != 0) {
+ // If target is zero, this would force actual == target, which is too harsh.
+ // Relax this requirement a little. The value is determined empirically from the
+ // coefficients computed by the quadratic least squares algorithms.
+ tolerance = 1E-6;
}
- if (fabsf(Vactual) > Vupper) {
- FAIL() << StringPrintf("Velocity %f is more than %.0f%% above target velocity %f",
- Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
- }
- SUCCEED() << StringPrintf("Velocity %f within %.0f%% of target %f)",
- Vactual, VELOCITY_TOLERANCE * 100, Vtarget);
+ EXPECT_NEAR(actual, target, tolerance);
+}
+
+static void checkVelocity(float Vactual, float Vtarget) {
+ EXPECT_NEAR_BY_FRACTION(Vactual, Vtarget, VELOCITY_TOLERANCE);
+}
+
+static void checkCoefficient(float actual, float target) {
+ EXPECT_NEAR_BY_FRACTION(actual, target, COEFFICIENT_TOLERANCE);
}
void failWithMessage(std::string message) {
@@ -125,6 +132,19 @@
delete event;
}
+static void computeAndCheckQuadraticEstimate(const Position* positions, size_t numSamples,
+ const std::array<float, 3>& coefficients) {
+ VelocityTracker vt("lsq2");
+ MotionEvent* event = createSimpleMotionEvent(positions, numSamples);
+ vt.addMovement(event);
+ VelocityTracker::Estimator estimator;
+ EXPECT_TRUE(vt.getEstimator(0, &estimator));
+ for (size_t i = 0; i< coefficients.size(); i++) {
+ checkCoefficient(estimator.xCoeff[i], coefficients[i]);
+ checkCoefficient(estimator.yCoeff[i], coefficients[i]);
+ }
+}
+
/*
* ================== VelocityTracker tests generated manually =====================================
*/
@@ -662,5 +682,114 @@
computeAndCheckVelocity(values, count, AMOTION_EVENT_AXIS_Y, 28354.796875); // lsq2
}
+/*
+ * Special care must be taken when constructing tests for LeastSquaresVelocityTrackerStrategy
+ * getEstimator function. In particular:
+ * - inside the function, time gets converted from nanoseconds to seconds
+ * before being used in the fit.
+ * - any values that are older than 100 ms are being discarded.
+ * - the newest time gets subtracted from all of the other times before being used in the fit.
+ * So these tests have to be designed with those limitations in mind.
+ *
+ * General approach for the tests below:
+ * We only used timestamps in milliseconds, 0 ms, 1 ms, and 2 ms, to be sure that
+ * we are well within the HORIZON range.
+ * When specifying the expected values of the coefficients, we treat the x values as if
+ * they were in ms. Then, to adjust for the time units, the coefficients get progressively
+ * multiplied by powers of 1E3.
+ * For example:
+ * data: t(ms), x
+ * 1 ms, 1
+ * 2 ms, 4
+ * 3 ms, 9
+ * The coefficients are (0, 0, 1).
+ * In the test, we would convert these coefficients to (0*(1E3)^0, 0*(1E3)^1, 1*(1E3)^2).
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Constant) {
+ Position values[] = {
+ { 0000000, 1, 1 }, // 0 s
+ { 1000000, 1, 1 }, // 0.001 s
+ { 2000000, 1, 1 }, // 0.002 s
+ };
+ // The data used for the fit will be as follows:
+ // time(s), position
+ // -0.002, 1
+ // -0.001, 1
+ // -0.000, 1
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({1, 0, 0}));
+}
+
+/*
+ * Straight line y = x :: the constant and quadratic coefficients are zero.
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Linear) {
+ Position values[] = {
+ { 0000000, -2, -2 },
+ { 1000000, -1, -1 },
+ { 2000000, -0, -0 },
+ };
+ // The data used for the fit will be as follows:
+ // time(s), position
+ // -0.002, -2
+ // -0.001, -1
+ // -0.000, 0
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({0, 1E3, 0}));
+}
+
+/*
+ * Parabola
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic) {
+ Position values[] = {
+ { 0000000, 1, 1 },
+ { 1000000, 4, 4 },
+ { 2000000, 8, 8 },
+ };
+ // The data used for the fit will be as follows:
+ // time(s), position
+ // -0.002, 1
+ // -0.001, 4
+ // -0.000, 8
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({8, 4.5E3, 0.5E6}));
+}
+
+/*
+ * Parabola
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic2) {
+ Position values[] = {
+ { 0000000, 1, 1 },
+ { 1000000, 4, 4 },
+ { 2000000, 9, 9 },
+ };
+ // The data used for the fit will be as follows:
+ // time(s), position
+ // -0.002, 1
+ // -0.001, 4
+ // -0.000, 9
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({9, 6E3, 1E6}));
+}
+
+/*
+ * Parabola :: y = x^2 :: the constant and linear coefficients are zero.
+ */
+TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic3) {
+ Position values[] = {
+ { 0000000, 4, 4 },
+ { 1000000, 1, 1 },
+ { 2000000, 0, 0 },
+ };
+ // The data used for the fit will be as follows:
+ // time(s), position
+ // -0.002, 4
+ // -0.001, 1
+ // -0.000, 0
+ size_t count = sizeof(values) / sizeof(Position);
+ computeAndCheckQuadraticEstimate(values, count, std::array<float, 3>({0, 0E3, 1E6}));
+}
} // namespace android
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 1605050..24b1986 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -54,6 +54,8 @@
srcs: [
"ColorSpace.cpp",
+ "BufferHubBuffer.cpp",
+ "BufferHubMetadata.cpp",
"DebugUtils.cpp",
"Fence.cpp",
"FenceTime.cpp",
@@ -91,6 +93,7 @@
"libutils",
"libutilscallstack",
"liblog",
+ "libpdx_default_transport", // TODO(b/112338294): Remove this once BufferHub moved to use Binder.
],
export_shared_lib_headers: [
@@ -103,8 +106,27 @@
"libmath",
],
+ // bufferhub is not used when building libgui for vendors
+ target: {
+ vendor: {
+ exclude_srcs: [
+ "BufferHubBuffer.cpp",
+ "BufferHubMetadata.cpp",
+ ],
+ exclude_header_libs: [
+ "libbufferhub_headers",
+ "libdvr_headers",
+ ],
+ exclude_shared_libs: [
+ "libpdx_default_transport",
+ ],
+ },
+ },
+
header_libs: [
"libbase_headers",
+ "libbufferhub_headers",
+ "libdvr_headers",
"libnativebase_headers",
"libhardware_headers",
"libui_headers",
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
new file mode 100644
index 0000000..606386c
--- /dev/null
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+
+// We would eliminate the clang warnings introduced by libdpx.
+// TODO(b/112338294): Remove those once BufferHub moved to use Binder
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wdouble-promotion"
+#pragma clang diagnostic ignored "-Wgnu-case-range"
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+#pragma clang diagnostic ignored "-Wpacked"
+#pragma clang diagnostic ignored "-Wshadow"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wswitch-enum"
+#pragma clang diagnostic ignored "-Wundefined-func-template"
+#pragma clang diagnostic ignored "-Wunused-template"
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#include <pdx/default_transport/client_channel.h>
+#include <pdx/default_transport/client_channel_factory.h>
+#include <pdx/file_handle.h>
+#include <private/dvr/bufferhub_rpc.h>
+#pragma clang diagnostic pop
+
+#include <ui/BufferHubBuffer.h>
+#include <ui/DetachedBufferHandle.h>
+
+#include <poll.h>
+
+using android::dvr::BufferHubMetadata;
+using android::dvr::BufferTraits;
+using android::dvr::DetachedBufferRPC;
+using android::dvr::NativeHandleWrapper;
+
+// TODO(b/112338294): Remove PDX dependencies from libui.
+using android::pdx::LocalChannelHandle;
+using android::pdx::LocalHandle;
+using android::pdx::Status;
+using android::pdx::default_transport::ClientChannel;
+using android::pdx::default_transport::ClientChannelFactory;
+
+namespace android {
+
+namespace {
+
+// TODO(b/112338294): Remove this string literal after refactoring BufferHub
+// to use Binder.
+static constexpr char kBufferHubClientPath[] = "system/buffer_hub/client";
+
+} // namespace
+
+BufferHubClient::BufferHubClient() : Client(ClientChannelFactory::Create(kBufferHubClientPath)) {}
+
+BufferHubClient::BufferHubClient(LocalChannelHandle mChannelHandle)
+ : Client(ClientChannel::Create(std::move(mChannelHandle))) {}
+
+BufferHubClient::~BufferHubClient() {}
+
+bool BufferHubClient::IsValid() const {
+ return IsConnected() && GetChannelHandle().valid();
+}
+
+LocalChannelHandle BufferHubClient::TakeChannelHandle() {
+ if (IsConnected()) {
+ return std::move(GetChannelHandle());
+ } else {
+ return {};
+ }
+}
+
+BufferHubBuffer::BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
+ uint32_t format, uint64_t usage, size_t mUserMetadataSize) {
+ ATRACE_CALL();
+ ALOGD("BufferHubBuffer::BufferHubBuffer: width=%u height=%u layerCount=%u, format=%u "
+ "usage=%" PRIx64 " mUserMetadataSize=%zu",
+ width, height, layerCount, format, usage, mUserMetadataSize);
+
+ auto status =
+ mClient.InvokeRemoteMethod<DetachedBufferRPC::Create>(width, height, layerCount, format,
+ usage, mUserMetadataSize);
+ if (!status) {
+ ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to create detached buffer: %s",
+ status.GetErrorMessage().c_str());
+ mClient.Close(-status.error());
+ }
+
+ const int ret = ImportGraphicBuffer();
+ if (ret < 0) {
+ ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import buffer: %s", strerror(-ret));
+ mClient.Close(ret);
+ }
+}
+
+BufferHubBuffer::BufferHubBuffer(LocalChannelHandle mChannelHandle)
+ : mClient(std::move(mChannelHandle)) {
+ const int ret = ImportGraphicBuffer();
+ if (ret < 0) {
+ ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import buffer: %s", strerror(-ret));
+ mClient.Close(ret);
+ }
+}
+
+int BufferHubBuffer::ImportGraphicBuffer() {
+ ATRACE_CALL();
+
+ auto status = mClient.InvokeRemoteMethod<DetachedBufferRPC::Import>();
+ if (!status) {
+ ALOGE("BufferHubBuffer::BufferHubBuffer: Failed to import GraphicBuffer: %s",
+ status.GetErrorMessage().c_str());
+ return -status.error();
+ }
+
+ BufferTraits<LocalHandle> bufferTraits = status.take();
+ if (bufferTraits.id() < 0) {
+ ALOGE("BufferHubBuffer::BufferHubBuffer: Received an invalid id!");
+ return -EIO;
+ }
+
+ // Stash the buffer id to replace the value in mId.
+ const int bufferId = bufferTraits.id();
+
+ // Import the metadata.
+ mMetadata = BufferHubMetadata::Import(bufferTraits.take_metadata_handle());
+
+ if (!mMetadata.IsValid()) {
+ ALOGE("BufferHubBuffer::ImportGraphicBuffer: invalid metadata.");
+ return -ENOMEM;
+ }
+
+ if (mMetadata.metadata_size() != bufferTraits.metadata_size()) {
+ ALOGE("BufferHubBuffer::ImportGraphicBuffer: metadata buffer too small: "
+ "%zu, expected: %" PRIu64 ".",
+ mMetadata.metadata_size(), bufferTraits.metadata_size());
+ return -ENOMEM;
+ }
+
+ size_t metadataSize = static_cast<size_t>(bufferTraits.metadata_size());
+ if (metadataSize < dvr::BufferHubDefs::kMetadataHeaderSize) {
+ ALOGE("BufferHubBuffer::ImportGraphicBuffer: metadata too small: %zu", metadataSize);
+ return -EINVAL;
+ }
+
+ // Import the buffer: We only need to hold on the native_handle_t here so that
+ // GraphicBuffer instance can be created in future.
+ mBufferHandle = bufferTraits.take_buffer_handle();
+
+ // If all imports succeed, replace the previous buffer and id.
+ mId = bufferId;
+ mBfferStateBit = bufferTraits.buffer_state_bit();
+
+ // TODO(b/112012161) Set up shared fences.
+ ALOGD("BufferHubBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64 ".", id(),
+ mMetadata.metadata_header()->buffer_state.load(std::memory_order_acquire));
+ return 0;
+}
+
+int BufferHubBuffer::Poll(int timeoutMs) {
+ ATRACE_CALL();
+
+ pollfd p = {mClient.event_fd(), POLLIN, 0};
+ return poll(&p, 1, timeoutMs);
+}
+
+Status<LocalChannelHandle> BufferHubBuffer::Promote() {
+ ATRACE_CALL();
+
+ // TODO(b/112338294) remove after migrate producer buffer to binder
+ ALOGW("BufferHubBuffer::Promote: not supported operation during migration");
+ return {};
+
+ ALOGD("BufferHubBuffer::Promote: id=%d.", mId);
+
+ auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Promote>();
+ if (statusOrHandle.ok()) {
+ // Invalidate the buffer.
+ mBufferHandle = {};
+ } else {
+ ALOGE("BufferHubBuffer::Promote: Failed to promote buffer (id=%d): %s.", mId,
+ statusOrHandle.GetErrorMessage().c_str());
+ }
+ return statusOrHandle;
+}
+
+Status<LocalChannelHandle> BufferHubBuffer::Duplicate() {
+ ATRACE_CALL();
+ ALOGD("BufferHubBuffer::Duplicate: id=%d.", mId);
+
+ auto statusOrHandle = mClient.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
+
+ if (!statusOrHandle.ok()) {
+ ALOGE("BufferHubBuffer::Duplicate: Failed to duplicate buffer (id=%d): %s.", mId,
+ statusOrHandle.GetErrorMessage().c_str());
+ }
+ return statusOrHandle;
+}
+
+} // namespace android
diff --git a/libs/ui/BufferHubMetadata.cpp b/libs/ui/BufferHubMetadata.cpp
new file mode 100644
index 0000000..b0c4510
--- /dev/null
+++ b/libs/ui/BufferHubMetadata.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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 <errno.h>
+#include <sys/mman.h>
+
+#include <cutils/ashmem.h>
+#include <log/log.h>
+#include <ui/BufferHubMetadata.h>
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+static const int kAshmemProt = PROT_READ | PROT_WRITE;
+
+} // namespace
+
+using BufferHubDefs::kMetadataHeaderSize;
+using BufferHubDefs::MetadataHeader;
+
+/* static */
+BufferHubMetadata BufferHubMetadata::Create(size_t userMetadataSize) {
+ // The size the of metadata buffer is used as the "width" parameter during allocation. Thus it
+ // cannot overflow uint32_t.
+ if (userMetadataSize >= (std::numeric_limits<uint32_t>::max() - kMetadataHeaderSize)) {
+ ALOGE("BufferHubMetadata::Create: metadata size too big: %zu.", userMetadataSize);
+ return {};
+ }
+
+ const size_t metadataSize = userMetadataSize + kMetadataHeaderSize;
+ int fd = ashmem_create_region(/*name=*/"BufferHubMetadata", metadataSize);
+ if (fd < 0) {
+ ALOGE("BufferHubMetadata::Create: failed to create ashmem region.");
+ return {};
+ }
+
+ // Hand over the ownership of the fd to a pdx::LocalHandle immediately after the successful
+ // return of ashmem_create_region. The ashmemHandle is going to own the fd and to prevent fd
+ // leaks during error handling.
+ pdx::LocalHandle ashmemHandle{fd};
+
+ if (ashmem_set_prot_region(ashmemHandle.Get(), kAshmemProt) != 0) {
+ ALOGE("BufferHubMetadata::Create: failed to set protect region.");
+ return {};
+ }
+
+ return BufferHubMetadata::Import(std::move(ashmemHandle));
+}
+
+/* static */
+BufferHubMetadata BufferHubMetadata::Import(pdx::LocalHandle ashmemHandle) {
+ if (!ashmem_valid(ashmemHandle.Get())) {
+ ALOGE("BufferHubMetadata::Import: invalid ashmem fd.");
+ return {};
+ }
+
+ size_t metadataSize = static_cast<size_t>(ashmem_get_size_region(ashmemHandle.Get()));
+ size_t userMetadataSize = metadataSize - kMetadataHeaderSize;
+
+ // Note that here the buffer state is mapped from shared memory as an atomic object. The
+ // std::atomic's constructor will not be called so that the original value stored in the memory
+ // region can be preserved.
+ auto metadataHeader = static_cast<MetadataHeader*>(mmap(nullptr, metadataSize, kAshmemProt,
+ MAP_SHARED, ashmemHandle.Get(),
+ /*offset=*/0));
+ if (metadataHeader == nullptr) {
+ ALOGE("BufferHubMetadata::Import: failed to map region.");
+ return {};
+ }
+
+ return BufferHubMetadata(userMetadataSize, std::move(ashmemHandle), metadataHeader);
+}
+
+BufferHubMetadata::BufferHubMetadata(size_t userMetadataSize, pdx::LocalHandle ashmemHandle,
+ MetadataHeader* metadataHeader)
+ : mUserMetadataSize(userMetadataSize),
+ mAshmemHandle(std::move(ashmemHandle)),
+ mMetadataHeader(metadataHeader) {}
+
+BufferHubMetadata::~BufferHubMetadata() {
+ if (mMetadataHeader != nullptr) {
+ int ret = munmap(mMetadataHeader, metadata_size());
+ ALOGE_IF(ret != 0,
+ "BufferHubMetadata::~BufferHubMetadata: failed to unmap ashmem, error=%d.", errno);
+ mMetadataHeader = nullptr;
+ }
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 0382479..c50d1d0 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -376,6 +376,10 @@
status_t GraphicBuffer::unflatten(
void const*& buffer, size_t& size, int const*& fds, size_t& count) {
+ if (size < 12 * sizeof(int)) {
+ android_errorWriteLog(0x534e4554, "114223584");
+ return NO_MEMORY;
+ }
int const* buf = static_cast<int const*>(buffer);
diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp
index a36911d..a5b3e89 100644
--- a/libs/ui/HdrCapabilities.cpp
+++ b/libs/ui/HdrCapabilities.cpp
@@ -24,8 +24,8 @@
#endif
HdrCapabilities::~HdrCapabilities() = default;
-HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) = default;
-HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) = default;
+HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) noexcept = default;
+HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) noexcept = default;
size_t HdrCapabilities::getFlattenedSize() const {
return sizeof(mMaxLuminance) +
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
new file mode 100644
index 0000000..e8ae244
--- /dev/null
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -0,0 +1,149 @@
+/*
+ * 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_BUFFER_HUB_BUFFER_H_
+#define ANDROID_BUFFER_HUB_BUFFER_H_
+
+// We would eliminate the clang warnings introduced by libdpx.
+// TODO(b/112338294): Remove those once BufferHub moved to use Binder
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wdouble-promotion"
+#pragma clang diagnostic ignored "-Wgnu-case-range"
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+#pragma clang diagnostic ignored "-Wpacked"
+#pragma clang diagnostic ignored "-Wshadow"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wswitch-enum"
+#pragma clang diagnostic ignored "-Wundefined-func-template"
+#pragma clang diagnostic ignored "-Wunused-template"
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#include <pdx/client.h>
+#include <private/dvr/buffer_hub_defs.h>
+#include <private/dvr/native_handle_wrapper.h>
+#pragma clang diagnostic pop
+
+#include <ui/BufferHubMetadata.h>
+
+namespace android {
+
+class BufferHubClient : public pdx::Client {
+public:
+ BufferHubClient();
+ virtual ~BufferHubClient();
+ explicit BufferHubClient(pdx::LocalChannelHandle mChannelHandle);
+
+ bool IsValid() const;
+ pdx::LocalChannelHandle TakeChannelHandle();
+
+ using pdx::Client::Close;
+ using pdx::Client::event_fd;
+ using pdx::Client::GetChannel;
+ using pdx::Client::InvokeRemoteMethod;
+};
+
+class BufferHubBuffer {
+public:
+ // Allocates a standalone BufferHubBuffer not associated with any producer consumer set.
+ static std::unique_ptr<BufferHubBuffer> Create(uint32_t width, uint32_t height,
+ uint32_t layerCount, uint32_t format,
+ uint64_t usage, size_t mUserMetadataSize) {
+ return std::unique_ptr<BufferHubBuffer>(
+ new BufferHubBuffer(width, height, layerCount, format, usage, mUserMetadataSize));
+ }
+
+ // Imports the given channel handle to a BufferHubBuffer, taking ownership.
+ static std::unique_ptr<BufferHubBuffer> Import(pdx::LocalChannelHandle mChannelHandle) {
+ return std::unique_ptr<BufferHubBuffer>(new BufferHubBuffer(std::move(mChannelHandle)));
+ }
+
+ BufferHubBuffer(const BufferHubBuffer&) = delete;
+ void operator=(const BufferHubBuffer&) = delete;
+
+ // Gets ID of the buffer client. All BufferHubBuffer clients derived from the same buffer in
+ // bufferhubd share the same buffer id.
+ int id() const { return mId; }
+
+ const native_handle_t* DuplicateHandle() { return mBufferHandle.DuplicateHandle(); }
+
+ // Returns the current value of MetadataHeader::buffer_state.
+ uint64_t buffer_state() {
+ return mMetadata.metadata_header()->buffer_state.load(std::memory_order_acquire);
+ }
+
+ // A state mask which is unique to a buffer hub client among all its siblings sharing the same
+ // concrete graphic buffer.
+ uint64_t buffer_state_bit() const { return mBfferStateBit; }
+
+ size_t user_metadata_size() const { return mMetadata.user_metadata_size(); }
+
+ // Returns true if the buffer holds an open PDX channels towards bufferhubd.
+ bool IsConnected() const { return mClient.IsValid(); }
+
+ // Returns true if the buffer holds an valid native buffer handle that's availble for the client
+ // to read from and/or write into.
+ bool IsValid() const { return mBufferHandle.IsValid(); }
+
+ // Returns the event mask for all the events that are pending on this buffer (see sys/poll.h for
+ // all possible bits).
+ pdx::Status<int> GetEventMask(int events) {
+ if (auto* channel = mClient.GetChannel()) {
+ return channel->GetEventMask(events);
+ } else {
+ return pdx::ErrorStatus(EINVAL);
+ }
+ }
+
+ // Polls the fd for |timeoutMs| milliseconds (-1 for infinity).
+ int Poll(int timeoutMs);
+
+ // Promotes a BufferHubBuffer to become a ProducerBuffer. Once promoted the BufferHubBuffer
+ // channel will be closed automatically on successful IPC return. Further IPCs towards this
+ // channel will return error.
+ pdx::Status<pdx::LocalChannelHandle> Promote();
+
+ // Creates a BufferHubBuffer client from an existing one. The new client will
+ // share the same underlying gralloc buffer and ashmem region for metadata.
+ pdx::Status<pdx::LocalChannelHandle> Duplicate();
+
+private:
+ BufferHubBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint32_t format,
+ uint64_t usage, size_t mUserMetadataSize);
+
+ BufferHubBuffer(pdx::LocalChannelHandle mChannelHandle);
+
+ int ImportGraphicBuffer();
+
+ // Global id for the buffer that is consistent across processes.
+ int mId;
+ uint64_t mBfferStateBit;
+
+ // Wrapps the gralloc buffer handle of this buffer.
+ dvr::NativeHandleWrapper<pdx::LocalHandle> mBufferHandle;
+
+ // An ashmem-based metadata object. The same shared memory are mapped to the
+ // bufferhubd daemon and all buffer clients.
+ dvr::BufferHubMetadata mMetadata;
+
+ // PDX backend.
+ BufferHubClient mClient;
+};
+
+} // namespace android
+
+#endif // ANDROID_BUFFER_HUB_BUFFER_H_
diff --git a/libs/ui/include/ui/BufferHubMetadata.h b/libs/ui/include/ui/BufferHubMetadata.h
new file mode 100644
index 0000000..46adc6a
--- /dev/null
+++ b/libs/ui/include/ui/BufferHubMetadata.h
@@ -0,0 +1,106 @@
+/*
+ * 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_BUFFER_HUB_METADATA_H_
+#define ANDROID_BUFFER_HUB_METADATA_H_
+
+// We would eliminate the clang warnings introduced by libdpx.
+// TODO(b/112338294): Remove those once BufferHub moved to use Binder
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wdouble-promotion"
+#pragma clang diagnostic ignored "-Wgnu-case-range"
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#pragma clang diagnostic ignored "-Winconsistent-missing-destructor-override"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+#pragma clang diagnostic ignored "-Wpacked"
+#pragma clang diagnostic ignored "-Wshadow"
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wswitch-enum"
+#pragma clang diagnostic ignored "-Wundefined-func-template"
+#pragma clang diagnostic ignored "-Wunused-template"
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#include <pdx/file_handle.h>
+#include <private/dvr/buffer_hub_defs.h>
+#pragma clang diagnostic pop
+
+namespace android {
+namespace dvr {
+
+class BufferHubMetadata {
+public:
+ // Creates a new BufferHubMetadata backed by an ashmem region.
+ //
+ // @param userMetadataSize Size in bytes of the user defined metadata. The entire metadata
+ // shared memory region to be allocated is the size of canonical
+ // BufferHubDefs::MetadataHeader plus userMetadataSize.
+ static BufferHubMetadata Create(size_t userMetadataSize);
+
+ // Imports an existing BufferHubMetadata from an ashmem FD.
+ //
+ // TODO(b/112338294): Refactor BufferHub to use Binder as its internal IPC backend instead of
+ // UDS.
+ //
+ // @param ashmemHandle Ashmem file handle representing an ashmem region.
+ static BufferHubMetadata Import(pdx::LocalHandle ashmemHandle);
+
+ BufferHubMetadata() = default;
+
+ BufferHubMetadata(BufferHubMetadata&& other) { *this = std::move(other); }
+
+ ~BufferHubMetadata();
+
+ BufferHubMetadata& operator=(BufferHubMetadata&& other) {
+ if (this != &other) {
+ mUserMetadataSize = other.mUserMetadataSize;
+ other.mUserMetadataSize = 0;
+
+ mAshmemHandle = std::move(other.mAshmemHandle);
+
+ // The old raw mMetadataHeader pointer must be cleared, otherwise the destructor will
+ // automatically mummap() the shared memory.
+ mMetadataHeader = other.mMetadataHeader;
+ other.mMetadataHeader = nullptr;
+ }
+ return *this;
+ }
+
+ // Returns true if the metadata is valid, i.e. the metadata has a valid ashmem fd and the ashmem
+ // has been mapped into virtual address space.
+ bool IsValid() const { return mAshmemHandle.IsValid() && mMetadataHeader != nullptr; }
+
+ size_t user_metadata_size() const { return mUserMetadataSize; }
+ size_t metadata_size() const { return mUserMetadataSize + BufferHubDefs::kMetadataHeaderSize; }
+
+ const pdx::LocalHandle& ashmem_handle() const { return mAshmemHandle; }
+ BufferHubDefs::MetadataHeader* metadata_header() { return mMetadataHeader; }
+
+private:
+ BufferHubMetadata(size_t userMetadataSize, pdx::LocalHandle ashmemHandle,
+ BufferHubDefs::MetadataHeader* metadataHeader);
+
+ BufferHubMetadata(const BufferHubMetadata&) = delete;
+ void operator=(const BufferHubMetadata&) = delete;
+
+ size_t mUserMetadataSize = 0;
+ pdx::LocalHandle mAshmemHandle;
+ BufferHubDefs::MetadataHeader* mMetadataHeader = nullptr;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_BUFFER_HUB_METADATA_H_
diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h
index 4e98c28..65ac26c 100644
--- a/libs/ui/include/ui/HdrCapabilities.h
+++ b/libs/ui/include/ui/HdrCapabilities.h
@@ -37,8 +37,8 @@
mMinLuminance(minLuminance) {}
// Make this move-constructable and move-assignable
- HdrCapabilities(HdrCapabilities&& other);
- HdrCapabilities& operator=(HdrCapabilities&& other);
+ HdrCapabilities(HdrCapabilities&& other) noexcept;
+ HdrCapabilities& operator=(HdrCapabilities&& other) noexcept;
HdrCapabilities()
: mSupportedHdrTypes(),
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index aef6428..6e73960 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -34,3 +34,11 @@
srcs: ["GraphicBuffer_test.cpp"],
cflags: ["-Wall", "-Werror"],
}
+
+cc_test {
+ name: "BufferHubMetadata_test",
+ header_libs: ["libbufferhub_headers", "libdvr_headers"],
+ shared_libs: ["libpdx_default_transport", "libui", "libutils"],
+ srcs: ["BufferHubMetadata_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+}
diff --git a/libs/ui/tests/BufferHubMetadata_test.cpp b/libs/ui/tests/BufferHubMetadata_test.cpp
new file mode 100644
index 0000000..4209392
--- /dev/null
+++ b/libs/ui/tests/BufferHubMetadata_test.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <ui/BufferHubMetadata.h>
+
+using android::dvr::BufferHubDefs::IsBufferGained;
+
+namespace android {
+namespace dvr {
+
+constexpr size_t kEmptyUserMetadataSize = 0;
+
+class BufferHubMetadataTest : public ::testing::Test {};
+
+TEST_F(BufferHubMetadataTest, Create_UserMetdataSizeTooBig) {
+ BufferHubMetadata m1 =
+ BufferHubMetadata::Create(std::numeric_limits<uint32_t>::max());
+ EXPECT_FALSE(m1.IsValid());
+}
+
+TEST_F(BufferHubMetadataTest, Create_Success) {
+ BufferHubMetadata m1 = BufferHubMetadata::Create(kEmptyUserMetadataSize);
+ EXPECT_TRUE(m1.IsValid());
+ EXPECT_NE(m1.metadata_header(), nullptr);
+}
+
+TEST_F(BufferHubMetadataTest, Import_Success) {
+ BufferHubMetadata m1 = BufferHubMetadata::Create(kEmptyUserMetadataSize);
+ EXPECT_TRUE(m1.IsValid());
+ EXPECT_NE(m1.metadata_header(), nullptr);
+
+ pdx::LocalHandle h2 = m1.ashmem_handle().Duplicate();
+ EXPECT_TRUE(h2.IsValid());
+
+ BufferHubMetadata m2 = BufferHubMetadata::Import(std::move(h2));
+ EXPECT_FALSE(h2.IsValid());
+ EXPECT_TRUE(m1.IsValid());
+ BufferHubDefs::MetadataHeader* mh1 = m1.metadata_header();
+ EXPECT_NE(mh1, nullptr);
+
+ // TODO(b/111976433): Update this test once BufferHub state machine gets
+ // updated. In the old model, buffer starts in the gained state (i.e.
+ // valued 0). In the new model, buffer states in the released state.
+ EXPECT_TRUE(IsBufferGained(mh1->fence_state.load()));
+
+ EXPECT_TRUE(m2.IsValid());
+ BufferHubDefs::MetadataHeader* mh2 = m2.metadata_header();
+ EXPECT_NE(mh2, nullptr);
+
+ // TODO(b/111976433): Update this test once BufferHub state machine gets
+ // updated. In the old model, buffer starts in the gained state (i.e.
+ // valued 0). In the new model, buffer states in the released state.
+ EXPECT_TRUE(IsBufferGained(mh2->fence_state.load()));
+}
+
+TEST_F(BufferHubMetadataTest, MoveMetadataInvalidatesOldOne) {
+ BufferHubMetadata m1 = BufferHubMetadata::Create(sizeof(int));
+ EXPECT_TRUE(m1.IsValid());
+ EXPECT_NE(m1.metadata_header(), nullptr);
+ EXPECT_TRUE(m1.ashmem_handle().IsValid());
+ EXPECT_EQ(m1.user_metadata_size(), sizeof(int));
+
+ BufferHubMetadata m2 = std::move(m1);
+
+ // After the move, the metadata header (a raw pointer) should be reset in the
+ // older buffer.
+ EXPECT_EQ(m1.metadata_header(), nullptr);
+ EXPECT_NE(m2.metadata_header(), nullptr);
+
+ EXPECT_FALSE(m1.ashmem_handle().IsValid());
+ EXPECT_TRUE(m2.ashmem_handle().IsValid());
+
+ EXPECT_EQ(m1.user_metadata_size(), 0U);
+ EXPECT_EQ(m2.user_metadata_size(), sizeof(int));
+
+ BufferHubMetadata m3{std::move(m2)};
+
+ // After the move, the metadata header (a raw pointer) should be reset in the
+ // older buffer.
+ EXPECT_EQ(m2.metadata_header(), nullptr);
+ EXPECT_NE(m3.metadata_header(), nullptr);
+
+ EXPECT_FALSE(m2.ashmem_handle().IsValid());
+ EXPECT_TRUE(m3.ashmem_handle().IsValid());
+
+ EXPECT_EQ(m2.user_metadata_size(), 0U);
+ EXPECT_EQ(m3.user_metadata_size(), sizeof(int));
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index edc9131..ba5cfcd 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -12,20 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+cc_library_headers {
+ name: "libbufferhub_headers",
+ export_include_dirs: ["include"],
+ vendor_available: true, // TODO(b/112338314): Does shouldn't be available to vendor.
+}
+
sourceFiles = [
"buffer_hub_base.cpp",
- "buffer_hub_client.cpp",
"buffer_hub_rpc.cpp",
"consumer_buffer.cpp",
- "detached_buffer.cpp",
"ion_buffer.cpp",
"producer_buffer.cpp",
]
-localIncludeFiles = [
- "include",
-]
-
sharedLibraries = [
"libbase",
"libbinder",
@@ -39,6 +39,7 @@
]
headerLibraries = [
+ "libbufferhub_headers",
"libdvr_headers",
"libnativebase_headers",
]
@@ -52,13 +53,16 @@
"-Wall",
"-Werror",
],
- export_include_dirs: localIncludeFiles,
shared_libs: sharedLibraries,
header_libs: headerLibraries,
name: "libbufferhub",
export_header_lib_headers: [
+ "libbufferhub_headers",
"libnativebase_headers",
],
+
+ // TODO(b/117568153): Temporarily opt out using libcrt.
+ no_libcrt: true,
}
cc_test {
@@ -67,5 +71,7 @@
shared_libs: sharedLibraries,
header_libs: headerLibraries,
name: "buffer_hub-test",
-}
+ // TODO(b/117568153): Temporarily opt out using libcrt.
+ no_libcrt: true,
+}
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 11b2211..b477f1a 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -2,9 +2,9 @@
#include <poll.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/bufferhub_rpc.h>
-#include <private/dvr/detached_buffer.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
+#include <ui/BufferHubBuffer.h>
#include <ui/DetachedBufferHandle.h>
#include <mutex>
@@ -19,11 +19,11 @@
return result; \
})()
+using android::BufferHubBuffer;
using android::GraphicBuffer;
using android::sp;
-using android::dvr::BufferConsumer;
-using android::dvr::BufferProducer;
-using android::dvr::DetachedBuffer;
+using android::dvr::ConsumerBuffer;
+using android::dvr::ProducerBuffer;
using android::dvr::BufferHubDefs::IsBufferAcquired;
using android::dvr::BufferHubDefs::IsBufferGained;
using android::dvr::BufferHubDefs::IsBufferPosted;
@@ -41,22 +41,21 @@
const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
const int kUsage = 0;
const size_t kUserMetadataSize = 0;
-const uint64_t kContext = 42;
const size_t kMaxConsumerCount = 63;
const int kPollTimeoutMs = 100;
using LibBufferHubTest = ::testing::Test;
TEST_F(LibBufferHubTest, TestBasicUsage) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
// Check that consumers can spawn other consumers.
- std::unique_ptr<BufferConsumer> c2 =
- BufferConsumer::Import(c->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c2 =
+ ConsumerBuffer::Import(c->CreateConsumer());
ASSERT_TRUE(c2.get() != nullptr);
// Producer state mask is unique, i.e. 1.
@@ -79,22 +78,19 @@
EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+ EXPECT_EQ(0, p->Post(LocalHandle()));
// New state: producer not available, consumers available.
EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
EXPECT_EQ(1, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
- uint64_t context;
LocalHandle fence;
- EXPECT_EQ(0, c->Acquire(&fence, &context));
- EXPECT_EQ(kContext, context);
+ EXPECT_EQ(0, c->Acquire(&fence));
EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
EXPECT_EQ(1, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
- EXPECT_EQ(0, c2->Acquire(&fence, &context));
- EXPECT_EQ(kContext, context);
+ EXPECT_EQ(0, c2->Acquire(&fence));
EXPECT_EQ(0, RETRY_EINTR(c2->Poll(kPollTimeoutMs)));
EXPECT_EQ(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
@@ -110,11 +106,11 @@
}
TEST_F(LibBufferHubTest, TestEpoll) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
LocalHandle epoll_fd{epoll_create1(EPOLL_CLOEXEC)};
@@ -147,7 +143,7 @@
ASSERT_EQ(0, epoll_wait(epoll_fd.Get(), events.data(), events.size(), 0));
// Post the producer and check for consumer signal.
- EXPECT_EQ(0, p->Post({}, kContext));
+ EXPECT_EQ(0, p->Post({}));
ASSERT_EQ(1, epoll_wait(epoll_fd.Get(), events.data(), events.size(),
kPollTimeoutMs));
ASSERT_TRUE(events[0].events & EPOLLIN);
@@ -177,15 +173,15 @@
}
TEST_F(LibBufferHubTest, TestStateMask) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
// It's ok to create up to kMaxConsumerCount consumer buffers.
uint64_t buffer_state_bits = p->buffer_state_bit();
- std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs;
+ std::array<std::unique_ptr<ConsumerBuffer>, kMaxConsumerCount> cs;
for (size_t i = 0; i < kMaxConsumerCount; i++) {
- cs[i] = BufferConsumer::Import(p->CreateConsumer());
+ cs[i] = ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(cs[i].get() != nullptr);
// Expect all buffers have unique state mask.
EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U);
@@ -201,7 +197,7 @@
for (size_t i = 0; i < kMaxConsumerCount; i++) {
buffer_state_bits &= ~cs[i]->buffer_state_bit();
cs[i] = nullptr;
- cs[i] = BufferConsumer::Import(p->CreateConsumer());
+ cs[i] = ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(cs[i].get() != nullptr);
// The released state mask will be reused.
EXPECT_EQ(buffer_state_bits & cs[i]->buffer_state_bit(), 0U);
@@ -211,11 +207,11 @@
}
TEST_F(LibBufferHubTest, TestStateTransitions) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
uint64_t context;
@@ -229,10 +225,10 @@
EXPECT_EQ(-EALREADY, p->Gain(&fence));
// Post in gained state should succeed.
- EXPECT_EQ(0, p->Post(LocalHandle(), kContext));
+ EXPECT_EQ(0, p->Post(LocalHandle()));
// Post, release, and gain in posted state should fail.
- EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+ EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
EXPECT_EQ(-EBUSY, p->Gain(&fence));
@@ -241,7 +237,7 @@
// Acquire, post, and gain in acquired state should fail.
EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
- EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+ EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
EXPECT_EQ(-EBUSY, p->Gain(&fence));
// Release in acquired state should succeed.
@@ -251,7 +247,7 @@
// Release, acquire, and post in released state should fail.
EXPECT_EQ(-EBUSY, c->Release(LocalHandle()));
EXPECT_EQ(-EBUSY, c->Acquire(&fence, &context));
- EXPECT_EQ(-EBUSY, p->Post(LocalHandle(), kContext));
+ EXPECT_EQ(-EBUSY, p->Post(LocalHandle()));
// Gain in released state should succeed.
EXPECT_EQ(0, p->Gain(&fence));
@@ -263,11 +259,11 @@
}
TEST_F(LibBufferHubTest, TestAsyncStateTransitions) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
DvrNativeBufferMetadata metadata;
@@ -334,7 +330,7 @@
}
TEST_F(LibBufferHubTest, TestZeroConsumer) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
@@ -350,21 +346,21 @@
EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
// A new consumer should still be able to acquire the buffer immediately.
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
EXPECT_TRUE(IsBufferAcquired(c->buffer_state()));
}
TEST_F(LibBufferHubTest, TestMaxConsumers) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
- std::array<std::unique_ptr<BufferConsumer>, kMaxConsumerCount> cs;
+ std::array<std::unique_ptr<ConsumerBuffer>, kMaxConsumerCount> cs;
for (size_t i = 0; i < kMaxConsumerCount; i++) {
- cs[i] = BufferConsumer::Import(p->CreateConsumer());
+ cs[i] = ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(cs[i].get() != nullptr);
EXPECT_TRUE(IsBufferGained(cs[i]->buffer_state()));
}
@@ -400,13 +396,13 @@
}
TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferGained) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
EXPECT_TRUE(IsBufferGained(p->buffer_state()));
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
EXPECT_TRUE(IsBufferGained(c->buffer_state()));
@@ -422,7 +418,7 @@
}
TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferPosted) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
EXPECT_TRUE(IsBufferGained(p->buffer_state()));
@@ -435,8 +431,8 @@
EXPECT_TRUE(IsBufferPosted(p->buffer_state()));
// Newly created consumer should be automatically sigalled.
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
EXPECT_TRUE(IsBufferPosted(c->buffer_state()));
EXPECT_EQ(0, c->AcquireAsync(&metadata, &invalid_fence));
@@ -444,12 +440,12 @@
}
TEST_F(LibBufferHubTest, TestCreateConsumerWhenBufferReleased) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c1 =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c1 =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c1.get() != nullptr);
DvrNativeBufferMetadata metadata;
@@ -470,8 +466,8 @@
// Create another consumer immediately after the release, should not make the
// buffer un-released.
- std::unique_ptr<BufferConsumer> c2 =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c2 =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c2.get() != nullptr);
EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
@@ -484,23 +480,20 @@
int64_t field1;
int64_t field2;
};
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
-
Metadata m = {1, 3};
- EXPECT_EQ(0, p->Post(LocalHandle(), m));
+ EXPECT_EQ(0, p->Post(LocalHandle(), &m, sizeof(Metadata)));
EXPECT_LE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
-
LocalHandle fence;
Metadata m2 = {};
EXPECT_EQ(0, c->Acquire(&fence, &m2));
EXPECT_EQ(m.field1, m2.field1);
EXPECT_EQ(m.field2, m2.field2);
-
EXPECT_EQ(0, c->Release(LocalHandle()));
EXPECT_LT(0, RETRY_EINTR(p->Poll(0)));
}
@@ -515,23 +508,22 @@
int64_t field2;
int64_t field3;
};
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
// It is illegal to post metadata larger than originally requested during
// buffer allocation.
OverSizedMetadata evil_meta = {};
- EXPECT_NE(0, p->Post(LocalHandle(), evil_meta));
+ EXPECT_NE(0, p->Post(LocalHandle(), &evil_meta, sizeof(OverSizedMetadata)));
EXPECT_GE(0, RETRY_EINTR(c->Poll(kPollTimeoutMs)));
// It is ok to post metadata smaller than originally requested during
// buffer allocation.
- int64_t sequence = 42;
- EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
+ EXPECT_EQ(0, p->Post(LocalHandle()));
}
TEST_F(LibBufferHubTest, TestAcquireWithWrongMetaSize) {
@@ -544,15 +536,15 @@
int64_t field2;
int64_t field3;
};
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(Metadata));
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
Metadata m = {1, 3};
- EXPECT_EQ(0, p->Post(LocalHandle(), m));
+ EXPECT_EQ(0, p->Post(LocalHandle(), &m, sizeof(m)));
LocalHandle fence;
int64_t sequence;
@@ -569,26 +561,26 @@
}
TEST_F(LibBufferHubTest, TestAcquireWithNoMeta) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
int64_t sequence = 3;
- EXPECT_EQ(0, p->Post(LocalHandle(), sequence));
+ EXPECT_EQ(0, p->Post(LocalHandle(), &sequence, sizeof(sequence)));
LocalHandle fence;
EXPECT_EQ(0, c->Acquire(&fence));
}
TEST_F(LibBufferHubTest, TestWithNoMeta) {
- std::unique_ptr<BufferProducer> p =
- BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
+ std::unique_ptr<ProducerBuffer> p =
+ ProducerBuffer::Create(kWidth, kHeight, kFormat, kUsage);
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
LocalHandle fence;
@@ -598,15 +590,15 @@
}
TEST_F(LibBufferHubTest, TestFailureToPostMetaFromABufferWithoutMeta) {
- std::unique_ptr<BufferProducer> p =
- BufferProducer::Create(kWidth, kHeight, kFormat, kUsage);
+ std::unique_ptr<ProducerBuffer> p =
+ ProducerBuffer::Create(kWidth, kHeight, kFormat, kUsage);
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
int64_t sequence = 3;
- EXPECT_NE(0, p->Post(LocalHandle(), sequence));
+ EXPECT_NE(0, p->Post(LocalHandle(), &sequence, sizeof(sequence)));
}
namespace {
@@ -619,11 +611,11 @@
} // namespace
TEST_F(LibBufferHubTest, TestAcquireFence) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, /*metadata_size=*/0);
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c.get() != nullptr);
DvrNativeBufferMetadata meta;
@@ -680,11 +672,11 @@
}
TEST_F(LibBufferHubTest, TestOrphanedAcquire) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p.get() != nullptr);
- std::unique_ptr<BufferConsumer> c1 =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c1 =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c1.get() != nullptr);
const uint64_t consumer_state_bit1 = c1->buffer_state_bit();
@@ -699,8 +691,8 @@
c1 = nullptr;
EXPECT_GE(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- std::unique_ptr<BufferConsumer> c2 =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c2 =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c2.get() != nullptr);
const uint64_t consumer_state_bit2 = c2->buffer_state_bit();
EXPECT_NE(consumer_state_bit1, consumer_state_bit2);
@@ -715,8 +707,8 @@
EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
// But if another consumer is created in released state.
- std::unique_ptr<BufferConsumer> c3 =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c3 =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c3.get() != nullptr);
const uint64_t consumer_state_bit3 = c3->buffer_state_bit();
EXPECT_NE(consumer_state_bit2, consumer_state_bit3);
@@ -729,10 +721,13 @@
}
TEST_F(LibBufferHubTest, TestDetachBufferFromProducer) {
- std::unique_ptr<BufferProducer> p = BufferProducer::Create(
+ // TODO(b/112338294) rewrite test after migration
+ return;
+
+ std::unique_ptr<ProducerBuffer> p = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
- std::unique_ptr<BufferConsumer> c =
- BufferConsumer::Import(p->CreateConsumer());
+ std::unique_ptr<ConsumerBuffer> c =
+ ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(p.get() != nullptr);
ASSERT_TRUE(c.get() != nullptr);
@@ -789,8 +784,9 @@
// is gone.
EXPECT_EQ(s3.error(), EPIPE);
- // Detached buffer handle can be use to construct a new DetachedBuffer object.
- auto d = DetachedBuffer::Import(std::move(handle));
+ // Detached buffer handle can be use to construct a new BufferHubBuffer
+ // object.
+ auto d = BufferHubBuffer::Import(std::move(handle));
EXPECT_FALSE(handle.valid());
EXPECT_TRUE(d->IsConnected());
EXPECT_TRUE(d->IsValid());
@@ -798,17 +794,17 @@
EXPECT_EQ(d->id(), p_id);
}
-TEST_F(LibBufferHubTest, TestCreateDetachedBufferFails) {
+TEST_F(LibBufferHubTest, TestCreateBufferHubBufferFails) {
// Buffer Creation will fail: BLOB format requires height to be 1.
- auto b1 = DetachedBuffer::Create(kWidth, /*height=2*/ 2, kLayerCount,
- /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage,
- kUserMetadataSize);
+ auto b1 = BufferHubBuffer::Create(kWidth, /*height=2*/ 2, kLayerCount,
+ /*format=*/HAL_PIXEL_FORMAT_BLOB, kUsage,
+ kUserMetadataSize);
EXPECT_FALSE(b1->IsConnected());
EXPECT_FALSE(b1->IsValid());
// Buffer Creation will fail: user metadata size too large.
- auto b2 = DetachedBuffer::Create(
+ auto b2 = BufferHubBuffer::Create(
kWidth, kHeight, kLayerCount, kFormat, kUsage,
/*user_metadata_size=*/std::numeric_limits<size_t>::max());
@@ -816,7 +812,7 @@
EXPECT_FALSE(b2->IsValid());
// Buffer Creation will fail: user metadata size too large.
- auto b3 = DetachedBuffer::Create(
+ auto b3 = BufferHubBuffer::Create(
kWidth, kHeight, kLayerCount, kFormat, kUsage,
/*user_metadata_size=*/std::numeric_limits<size_t>::max() -
kMetadataHeaderSize);
@@ -825,17 +821,20 @@
EXPECT_FALSE(b3->IsValid());
}
-TEST_F(LibBufferHubTest, TestCreateDetachedBuffer) {
- auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
- kUsage, kUserMetadataSize);
+TEST_F(LibBufferHubTest, TestCreateBufferHubBuffer) {
+ auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, kUserMetadataSize);
EXPECT_TRUE(b1->IsConnected());
EXPECT_TRUE(b1->IsValid());
EXPECT_NE(b1->id(), 0);
}
-TEST_F(LibBufferHubTest, TestPromoteDetachedBuffer) {
- auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
- kUsage, kUserMetadataSize);
+TEST_F(LibBufferHubTest, TestPromoteBufferHubBuffer) {
+ // TODO(b/112338294) rewrite test after migration
+ return;
+
+ auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, kUserMetadataSize);
int b1_id = b1->id();
EXPECT_TRUE(b1->IsValid());
@@ -856,7 +855,7 @@
LocalChannelHandle h1 = status_or_handle.take();
EXPECT_TRUE(h1.valid());
- std::unique_ptr<BufferProducer> p1 = BufferProducer::Import(std::move(h1));
+ std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Import(std::move(h1));
EXPECT_FALSE(h1.valid());
ASSERT_TRUE(p1 != nullptr);
int p1_id = p1->id();
@@ -867,7 +866,10 @@
}
TEST_F(LibBufferHubTest, TestDetachThenPromote) {
- std::unique_ptr<BufferProducer> p1 = BufferProducer::Create(
+ // TODO(b/112338294) rewrite test after migration
+ return;
+
+ std::unique_ptr<ProducerBuffer> p1 = ProducerBuffer::Create(
kWidth, kHeight, kFormat, kUsage, sizeof(uint64_t));
ASSERT_TRUE(p1.get() != nullptr);
int p1_id = p1->id();
@@ -878,8 +880,9 @@
LocalChannelHandle h1 = status_or_handle.take();
EXPECT_TRUE(h1.valid());
- // Detached buffer handle can be use to construct a new DetachedBuffer object.
- auto b1 = DetachedBuffer::Import(std::move(h1));
+ // Detached buffer handle can be use to construct a new BufferHubBuffer
+ // object.
+ auto b1 = BufferHubBuffer::Import(std::move(h1));
EXPECT_FALSE(h1.valid());
EXPECT_TRUE(b1->IsValid());
int b1_id = b1->id();
@@ -896,7 +899,7 @@
LocalChannelHandle h2 = status_or_handle.take();
EXPECT_TRUE(h2.valid());
- std::unique_ptr<BufferProducer> p2 = BufferProducer::Import(std::move(h2));
+ std::unique_ptr<ProducerBuffer> p2 = ProducerBuffer::Import(std::move(h2));
EXPECT_FALSE(h2.valid());
ASSERT_TRUE(p2 != nullptr);
int p2_id = p2->id();
@@ -906,11 +909,12 @@
EXPECT_TRUE(IsBufferGained(p2->buffer_state()));
}
-TEST_F(LibBufferHubTest, TestDuplicateDetachedBuffer) {
- auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
- kUsage, kUserMetadataSize);
+TEST_F(LibBufferHubTest, TestDuplicateBufferHubBuffer) {
+ auto b1 = BufferHubBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, kUserMetadataSize);
int b1_id = b1->id();
EXPECT_TRUE(b1->IsValid());
+ EXPECT_EQ(b1->user_metadata_size(), kUserMetadataSize);
auto status_or_handle = b1->Duplicate();
EXPECT_TRUE(status_or_handle);
@@ -923,9 +927,12 @@
LocalChannelHandle h2 = status_or_handle.take();
EXPECT_TRUE(h2.valid());
- std::unique_ptr<DetachedBuffer> b2 = DetachedBuffer::Import(std::move(h2));
+ std::unique_ptr<BufferHubBuffer> b2 = BufferHubBuffer::Import(std::move(h2));
EXPECT_FALSE(h2.valid());
ASSERT_TRUE(b2 != nullptr);
+ EXPECT_TRUE(b2->IsValid());
+ EXPECT_EQ(b2->user_metadata_size(), kUserMetadataSize);
+
int b2_id = b2->id();
// These two buffer instances are based on the same physical buffer under the
@@ -942,6 +949,9 @@
EXPECT_TRUE(IsBufferGained(b1->buffer_state()));
EXPECT_TRUE(IsBufferGained(b2->buffer_state()));
+ // TODO(b/112338294) rewrite test after migration
+ return;
+
// Promote the detached buffer should fail as b1 is no longer the exclusive
// owner of the buffer..
status_or_handle = b1->Promote();
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index b2bcda7..bc6aece 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -116,9 +116,10 @@
cid_ = buffer_desc.buffer_cid();
buffer_state_bit_ = buffer_desc.buffer_state_bit();
- // Note that here the buffer state is mapped from shared memory as an atomic
- // object. The std::atomic's constructor will not be called so that the
- // original value stored in the memory region will be preserved.
+ // Note that here the buffer_state, fence_state and active_clients_bit_mask
+ // are mapped from shared memory as an atomic object. The std::atomic's
+ // constructor will not be called so that the original value stored in the
+ // memory region will be preserved.
buffer_state_ = &metadata_header_->buffer_state;
ALOGD_IF(TRACE,
"BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx64 ".",
@@ -127,6 +128,12 @@
ALOGD_IF(TRACE,
"BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx64 ".", id(),
fence_state_->load());
+ active_clients_bit_mask_ = &metadata_header_->active_clients_bit_mask;
+ ALOGD_IF(
+ TRACE,
+ "BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx64
+ ".",
+ id(), active_clients_bit_mask_->load());
return 0;
}
@@ -209,10 +216,6 @@
return ret;
}
-int BufferHubBase::GetBlobReadOnlyPointer(size_t size, void** addr) {
- return GetBlobReadWritePointer(size, addr);
-}
-
void BufferHubBase::GetBlobFds(int* fds, size_t* fds_count,
size_t max_fds_count) const {
size_t numFds = static_cast<size_t>(native_handle()->numFds);
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
deleted file mode 100644
index 3f20024..0000000
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <mutex>
-
-#include <log/log.h>
-#include <pdx/default_transport/client_channel.h>
-#include <pdx/default_transport/client_channel_factory.h>
-#include <private/dvr/buffer_hub_client.h>
-#include <utils/Trace.h>
-
-using android::pdx::LocalChannelHandle;
-using android::pdx::default_transport::ClientChannel;
-using android::pdx::default_transport::ClientChannelFactory;
-
-namespace android {
-namespace dvr {
-
-BufferHubClient::BufferHubClient()
- : Client(ClientChannelFactory::Create(BufferHubRPC::kClientPath)) {}
-
-BufferHubClient::BufferHubClient(LocalChannelHandle channel_handle)
- : Client(ClientChannel::Create(std::move(channel_handle))) {}
-
-bool BufferHubClient::IsValid() const {
- return IsConnected() && GetChannelHandle().valid();
-}
-
-LocalChannelHandle BufferHubClient::TakeChannelHandle() {
- if (IsConnected()) {
- return std::move(GetChannelHandle());
- } else {
- return {};
- }
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp
index 4e8c36b..c9d8554 100644
--- a/libs/vr/libbufferhub/consumer_buffer.cpp
+++ b/libs/vr/libbufferhub/consumer_buffer.cpp
@@ -174,10 +174,5 @@
int ConsumerBuffer::Discard() { return Release(LocalHandle()); }
-int ConsumerBuffer::SetIgnore(bool ignore) {
- return ReturnStatusOrError(
- InvokeRemoteMethod<BufferHubRPC::ConsumerSetIgnore>(ignore));
-}
-
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libbufferhub/detached_buffer.cpp b/libs/vr/libbufferhub/detached_buffer.cpp
deleted file mode 100644
index 7716cfa..0000000
--- a/libs/vr/libbufferhub/detached_buffer.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-#include <private/dvr/detached_buffer.h>
-
-#include <pdx/file_handle.h>
-#include <ui/DetachedBufferHandle.h>
-
-#include <poll.h>
-
-using android::pdx::LocalChannelHandle;
-using android::pdx::LocalHandle;
-using android::pdx::Status;
-
-namespace android {
-namespace dvr {
-
-DetachedBuffer::DetachedBuffer(uint32_t width, uint32_t height,
- uint32_t layer_count, uint32_t format,
- uint64_t usage, size_t user_metadata_size) {
- ATRACE_NAME("DetachedBuffer::DetachedBuffer");
- ALOGD_IF(TRACE,
- "DetachedBuffer::DetachedBuffer: width=%u height=%u layer_count=%u, "
- "format=%u usage=%" PRIx64 " user_metadata_size=%zu",
- width, height, layer_count, format, usage, user_metadata_size);
-
- auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Create>(
- width, height, layer_count, format, usage, user_metadata_size);
- if (!status) {
- ALOGE(
- "DetachedBuffer::DetachedBuffer: Failed to create detached buffer: %s",
- status.GetErrorMessage().c_str());
- client_.Close(-status.error());
- }
-
- const int ret = ImportGraphicBuffer();
- if (ret < 0) {
- ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s",
- strerror(-ret));
- client_.Close(ret);
- }
-}
-
-DetachedBuffer::DetachedBuffer(LocalChannelHandle channel_handle)
- : client_(std::move(channel_handle)) {
- const int ret = ImportGraphicBuffer();
- if (ret < 0) {
- ALOGE("DetachedBuffer::DetachedBuffer: Failed to import buffer: %s",
- strerror(-ret));
- client_.Close(ret);
- }
-}
-
-int DetachedBuffer::ImportGraphicBuffer() {
- ATRACE_NAME("DetachedBuffer::ImportGraphicBuffer");
-
- auto status = client_.InvokeRemoteMethod<DetachedBufferRPC::Import>();
- if (!status) {
- ALOGE("DetachedBuffer::DetachedBuffer: Failed to import GraphicBuffer: %s",
- status.GetErrorMessage().c_str());
- return -status.error();
- }
-
- BufferDescription<LocalHandle> buffer_desc = status.take();
- if (buffer_desc.id() < 0) {
- ALOGE("DetachedBuffer::DetachedBuffer: Received an invalid id!");
- return -EIO;
- }
-
- // Stash the buffer id to replace the value in id_.
- const int buffer_id = buffer_desc.id();
-
- // Import the buffer.
- IonBuffer ion_buffer;
- ALOGD_IF(TRACE, "DetachedBuffer::DetachedBuffer: id=%d.", buffer_id);
-
- if (const int ret = buffer_desc.ImportBuffer(&ion_buffer)) {
- ALOGE("Failed to import GraphicBuffer, error=%d", ret);
- return ret;
- }
-
- // Import the metadata.
- IonBuffer metadata_buffer;
- if (const int ret = buffer_desc.ImportMetadata(&metadata_buffer)) {
- ALOGE("Failed to import metadata buffer, error=%d", ret);
- return ret;
- }
- size_t metadata_buf_size = metadata_buffer.width();
- if (metadata_buf_size < BufferHubDefs::kMetadataHeaderSize) {
- ALOGE("DetachedBuffer::ImportGraphicBuffer: metadata buffer too small: %zu",
- metadata_buf_size);
- return -EINVAL;
- }
-
- // If all imports succeed, replace the previous buffer and id.
- id_ = buffer_id;
- buffer_ = std::move(ion_buffer);
- metadata_buffer_ = std::move(metadata_buffer);
- user_metadata_size_ = metadata_buf_size - BufferHubDefs::kMetadataHeaderSize;
-
- void* metadata_ptr = nullptr;
- if (const int ret =
- metadata_buffer_.Lock(BufferHubDefs::kMetadataUsage, /*x=*/0,
- /*y=*/0, metadata_buf_size,
- /*height=*/1, &metadata_ptr)) {
- ALOGE("DetachedBuffer::ImportGraphicBuffer: Failed to lock metadata.");
- return ret;
- }
-
- // TODO(b/112012161) Set up shared fences.
-
- // Note that here the buffer state is mapped from shared memory as an atomic
- // object. The std::atomic's constructor will not be called so that the
- // original value stored in the memory region can be preserved.
- metadata_header_ = static_cast<BufferHubDefs::MetadataHeader*>(metadata_ptr);
- if (user_metadata_size_) {
- user_metadata_ptr_ = static_cast<void*>(metadata_header_ + 1);
- } else {
- user_metadata_ptr_ = nullptr;
- }
-
- id_ = buffer_desc.id();
- buffer_state_bit_ = buffer_desc.buffer_state_bit();
-
- ALOGD_IF(TRACE,
- "DetachedBuffer::ImportGraphicBuffer: id=%d, buffer_state=%" PRIx64
- ".",
- id(), metadata_header_->buffer_state.load());
- return 0;
-}
-
-int DetachedBuffer::Poll(int timeout_ms) {
- ATRACE_NAME("DetachedBuffer::Poll");
- pollfd p = {client_.event_fd(), POLLIN, 0};
- return poll(&p, 1, timeout_ms);
-}
-
-Status<LocalChannelHandle> DetachedBuffer::Promote() {
- ATRACE_NAME("DetachedBuffer::Promote");
- ALOGD_IF(TRACE, "DetachedBuffer::Promote: id=%d.", id_);
-
- auto status_or_handle =
- client_.InvokeRemoteMethod<DetachedBufferRPC::Promote>();
- if (status_or_handle.ok()) {
- // Invalidate the buffer.
- buffer_ = {};
- } else {
- ALOGE("DetachedBuffer::Promote: Failed to promote buffer (id=%d): %s.", id_,
- status_or_handle.GetErrorMessage().c_str());
- }
- return status_or_handle;
-}
-
-Status<LocalChannelHandle> DetachedBuffer::Duplicate() {
- ATRACE_NAME("DetachedBuffer::Duplicate");
- ALOGD_IF(TRACE, "DetachedBuffer::Duplicate: id=%d.", id_);
-
- auto status_or_handle =
- client_.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
-
- if (!status_or_handle.ok()) {
- ALOGE("DetachedBuffer::Duplicate: Failed to duplicate buffer (id=%d): %s.",
- id_, status_or_handle.GetErrorMessage().c_str());
- }
- return status_or_handle;
-}
-
-} // namespace dvr
-} // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index 24db241..282be46 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -39,11 +39,6 @@
// after calling this method.
int GetBlobReadWritePointer(size_t size, void** addr);
- // Gets a blob buffer that was created with ProducerBuffer::CreateBlob.
- // Locking and Unlocking is handled internally. There's no need to Unlock
- // after calling this method.
- int GetBlobReadOnlyPointer(size_t size, void** addr);
-
// Returns a dup'd file descriptor for accessing the blob shared memory. The
// caller takes ownership of the file descriptor and must close it or pass on
// ownership. Some GPU API extensions can take file descriptors to bind shared
@@ -139,6 +134,7 @@
void* user_metadata_ptr_{nullptr};
std::atomic<uint64_t>* buffer_state_{nullptr};
std::atomic<uint64_t>* fence_state_{nullptr};
+ std::atomic<uint64_t>* active_clients_bit_mask_{nullptr};
LocalHandle shared_acquire_fence_;
LocalHandle shared_release_fence_;
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index 7b317d1..1daeed9 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -1,30 +1,10 @@
#ifndef ANDROID_DVR_BUFFER_HUB_CLIENT_H_
#define ANDROID_DVR_BUFFER_HUB_CLIENT_H_
-#include <pdx/channel_handle.h>
-#include <pdx/client.h>
+// TODO(b/116855254): This header is completely deprecated and replaced by
+// consumer_buffer.h and producer_buffer.h. Remove this file once all references
+// to it has been removed.
#include <private/dvr/consumer_buffer.h>
#include <private/dvr/producer_buffer.h>
-namespace android {
-namespace dvr {
-
-class BufferHubClient : public pdx::Client {
- public:
- BufferHubClient();
- explicit BufferHubClient(pdx::LocalChannelHandle channel_handle);
-
- bool IsValid() const;
- pdx::LocalChannelHandle TakeChannelHandle();
-
- using pdx::Client::Close;
- using pdx::Client::GetChannel;
- using pdx::Client::InvokeRemoteMethod;
- using pdx::Client::IsConnected;
- using pdx::Client::event_fd;
-};
-
-} // namespace dvr
-} // namespace android
-
#endif // ANDROID_DVR_BUFFER_HUB_CLIENT_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index 8b2bf91..6d28d41 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -3,6 +3,11 @@
#include <dvr/dvr_api.h>
#include <hardware/gralloc.h>
+#include <pdx/channel_handle.h>
+#include <pdx/file_handle.h>
+#include <pdx/rpc/remote_method.h>
+#include <pdx/rpc/serializable.h>
+#include <private/dvr/native_handle_wrapper.h>
#include <atomic>
@@ -70,6 +75,7 @@
// and vendor HAL).
std::atomic<uint64_t> buffer_state;
std::atomic<uint64_t> fence_state;
+ std::atomic<uint64_t> active_clients_bit_mask;
uint64_t queue_index;
// Public data format, which should be updated with caution. See more details
@@ -77,13 +83,142 @@
DvrNativeBufferMetadata metadata;
};
-static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
+static_assert(sizeof(MetadataHeader) == 136, "Unexpected MetadataHeader size");
static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
} // namespace BufferHubDefs
+template <typename FileHandleType>
+class BufferTraits {
+ public:
+ BufferTraits() = default;
+ BufferTraits(const native_handle_t* buffer_handle,
+ const FileHandleType& metadata_handle, int id,
+ uint64_t buffer_state_bit, uint64_t metadata_size,
+ uint32_t width, uint32_t height, uint32_t layer_count,
+ uint32_t format, uint64_t usage, uint32_t stride,
+ const FileHandleType& acquire_fence_fd,
+ const FileHandleType& release_fence_fd)
+ : id_(id),
+ buffer_state_bit_(buffer_state_bit),
+ metadata_size_(metadata_size),
+ width_(width),
+ height_(height),
+ layer_count_(layer_count),
+ format_(format),
+ usage_(usage),
+ stride_(stride),
+ buffer_handle_(buffer_handle),
+ metadata_handle_(metadata_handle.Borrow()),
+ acquire_fence_fd_(acquire_fence_fd.Borrow()),
+ release_fence_fd_(release_fence_fd.Borrow()) {}
+
+ BufferTraits(BufferTraits&& other) = default;
+ BufferTraits& operator=(BufferTraits&& other) = default;
+
+ // ID of the buffer client. All BufferHubBuffer clients derived from the same
+ // buffer in bufferhubd share the same buffer id.
+ int id() const { return id_; }
+
+ // State mask of the buffer client. Each BufferHubBuffer client backed by the
+ // same buffer channel has uniqued state bit among its siblings. For a
+ // producer buffer the bit must be kProducerStateBit; for a consumer the bit
+ // must be one of the kConsumerStateMask.
+ uint64_t buffer_state_bit() const { return buffer_state_bit_; }
+ uint64_t metadata_size() const { return metadata_size_; }
+
+ uint32_t width() { return width_; }
+ uint32_t height() { return height_; }
+ uint32_t layer_count() { return layer_count_; }
+ uint32_t format() { return format_; }
+ uint64_t usage() { return usage_; }
+ uint32_t stride() { return stride_; }
+
+ const NativeHandleWrapper<FileHandleType>& buffer_handle() const {
+ return buffer_handle_;
+ }
+
+ NativeHandleWrapper<FileHandleType> take_buffer_handle() {
+ return std::move(buffer_handle_);
+ }
+ FileHandleType take_metadata_handle() { return std::move(metadata_handle_); }
+ FileHandleType take_acquire_fence() { return std::move(acquire_fence_fd_); }
+ FileHandleType take_release_fence() { return std::move(release_fence_fd_); }
+
+ private:
+ // BufferHub specific traits.
+ int id_ = -1;
+ uint64_t buffer_state_bit_;
+ uint64_t metadata_size_;
+
+ // Traits for a GraphicBuffer.
+ uint32_t width_;
+ uint32_t height_;
+ uint32_t layer_count_;
+ uint32_t format_;
+ uint64_t usage_;
+ uint32_t stride_;
+
+ // Native handle for the graphic buffer.
+ NativeHandleWrapper<FileHandleType> buffer_handle_;
+
+ // File handle of an ashmem that holds buffer metadata.
+ FileHandleType metadata_handle_;
+
+ // Pamameters for shared fences.
+ FileHandleType acquire_fence_fd_;
+ FileHandleType release_fence_fd_;
+
+ PDX_SERIALIZABLE_MEMBERS(BufferTraits<FileHandleType>, id_, buffer_state_bit_,
+ metadata_size_, stride_, width_, height_,
+ layer_count_, format_, usage_, buffer_handle_,
+ metadata_handle_, acquire_fence_fd_,
+ release_fence_fd_);
+
+ BufferTraits(const BufferTraits&) = delete;
+ void operator=(const BufferTraits&) = delete;
+};
+
+struct DetachedBufferRPC {
+ private:
+ enum {
+ kOpDetachedBufferBase = 1000,
+
+ // Allocates a standalone DetachedBuffer not associated with any producer
+ // consumer set.
+ kOpCreate,
+
+ // Imports the given channel handle to a DetachedBuffer, taking ownership.
+ kOpImport,
+
+ // Promotes a DetachedBuffer to become a ProducerBuffer. Once promoted the
+ // DetachedBuffer channel will be closed automatically on successful IPC
+ // return. Further IPCs towards this channel will return error.
+ kOpPromote,
+
+ // Creates a DetachedBuffer client from an existing one. The new client will
+ // share the same underlying gralloc buffer and ashmem region for metadata.
+ kOpDuplicate,
+ };
+
+ // Aliases.
+ using LocalChannelHandle = pdx::LocalChannelHandle;
+ using LocalHandle = pdx::LocalHandle;
+ using Void = pdx::rpc::Void;
+
+ public:
+ PDX_REMOTE_METHOD(Create, kOpCreate,
+ void(uint32_t width, uint32_t height, uint32_t layer_count,
+ uint32_t format, uint64_t usage,
+ size_t user_metadata_size));
+ PDX_REMOTE_METHOD(Import, kOpImport, BufferTraits<LocalHandle>(Void));
+ PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void));
+ PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));
+
+ PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
+};
+
} // namespace dvr
} // namespace android
-
#endif // ANDROID_DVR_BUFFER_HUB_DEFS_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index 225914a..7330aa1 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -38,8 +38,8 @@
opaque_ints_.push_back(buffer.handle()->data[fd_count + i]);
}
}
- NativeBufferHandle(NativeBufferHandle&& other) = default;
- NativeBufferHandle& operator=(NativeBufferHandle&& other) = default;
+ NativeBufferHandle(NativeBufferHandle&& other) noexcept = default;
+ NativeBufferHandle& operator=(NativeBufferHandle&& other) noexcept = default;
// Imports the native handle into the given IonBuffer instance.
int Import(IonBuffer* buffer) {
@@ -110,8 +110,8 @@
acquire_fence_fd_(acquire_fence_fd.Borrow()),
release_fence_fd_(release_fence_fd.Borrow()) {}
- BufferDescription(BufferDescription&& other) = default;
- BufferDescription& operator=(BufferDescription&& other) = default;
+ BufferDescription(BufferDescription&& other) noexcept = default;
+ BufferDescription& operator=(BufferDescription&& other) noexcept = default;
// ID of the buffer client. All BufferHub clients derived from the same buffer
// in bufferhubd share the same buffer id.
@@ -161,8 +161,8 @@
FenceHandle() = default;
explicit FenceHandle(int fence) : fence_{fence} {}
explicit FenceHandle(FileHandleType&& fence) : fence_{std::move(fence)} {}
- FenceHandle(FenceHandle&&) = default;
- FenceHandle& operator=(FenceHandle&&) = default;
+ FenceHandle(FenceHandle&&) noexcept = default;
+ FenceHandle& operator=(FenceHandle&&) noexcept = default;
explicit operator bool() const { return fence_.IsValid(); }
@@ -314,11 +314,8 @@
kOpProducerGain,
kOpConsumerAcquire,
kOpConsumerRelease,
- kOpConsumerSetIgnore,
kOpProducerBufferDetach,
kOpConsumerBufferDetach,
- kOpDetachedBufferCreate,
- kOpDetachedBufferPromote,
kOpCreateProducerQueue,
kOpCreateConsumerQueue,
kOpGetQueueInfo,
@@ -327,7 +324,6 @@
kOpProducerQueueRemoveBuffer,
kOpConsumerQueueImportBuffers,
// TODO(b/77153033): Separate all those RPC operations into subclasses.
- kOpDetachedBufferBase = 1000,
};
// Aliases.
@@ -348,7 +344,6 @@
PDX_REMOTE_METHOD(ConsumerAcquire, kOpConsumerAcquire, LocalFence(Void));
PDX_REMOTE_METHOD(ConsumerRelease, kOpConsumerRelease,
void(LocalFence release_fence));
- PDX_REMOTE_METHOD(ConsumerSetIgnore, kOpConsumerSetIgnore, void(bool ignore));
PDX_REMOTE_METHOD(ProducerBufferDetach, kOpProducerBufferDetach,
LocalChannelHandle(Void));
@@ -381,27 +376,6 @@
std::vector<std::pair<LocalChannelHandle, size_t>>(Void));
};
-struct DetachedBufferRPC final : public BufferHubRPC {
- private:
- enum {
- kOpCreate = kOpDetachedBufferBase,
- kOpImport,
- kOpPromote,
- kOpDuplicate,
- };
-
- public:
- PDX_REMOTE_METHOD(Create, kOpCreate,
- void(uint32_t width, uint32_t height, uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size));
- PDX_REMOTE_METHOD(Import, kOpImport, BufferDescription<LocalHandle>(Void));
- PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void));
- PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));
-
- PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
-};
-
} // namespace dvr
} // namespace android
diff --git a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
index 089eff8..2044c53 100644
--- a/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/consumer_buffer.h
@@ -76,13 +76,6 @@
// negative unix error code.
int Discard();
- // When set, this consumer is no longer notified when this buffer is
- // available. The system behaves as if Discard() is immediately called
- // whenever the buffer is posted. If ignore is set to true while a buffer is
- // pending, it will act as if Discard() was also called.
- // This returns zero or a negative unix error code.
- int SetIgnore(bool ignore);
-
private:
friend BASE;
diff --git a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
deleted file mode 100644
index e795f3b..0000000
--- a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
+++ /dev/null
@@ -1,98 +0,0 @@
-#ifndef ANDROID_DVR_DETACHED_BUFFER_H_
-#define ANDROID_DVR_DETACHED_BUFFER_H_
-
-#include <private/dvr/buffer_hub_client.h>
-
-namespace android {
-namespace dvr {
-
-class DetachedBuffer {
- public:
- // Allocates a standalone DetachedBuffer not associated with any producer
- // consumer set.
- static std::unique_ptr<DetachedBuffer> Create(uint32_t width, uint32_t height,
- uint32_t layer_count,
- uint32_t format, uint64_t usage,
- size_t user_metadata_size) {
- return std::unique_ptr<DetachedBuffer>(new DetachedBuffer(
- width, height, layer_count, format, usage, user_metadata_size));
- }
-
- // Imports the given channel handle to a DetachedBuffer, taking ownership.
- static std::unique_ptr<DetachedBuffer> Import(
- pdx::LocalChannelHandle channel_handle) {
- return std::unique_ptr<DetachedBuffer>(
- new DetachedBuffer(std::move(channel_handle)));
- }
-
- DetachedBuffer(const DetachedBuffer&) = delete;
- void operator=(const DetachedBuffer&) = delete;
-
- // Gets ID of the buffer client. All DetachedBuffer clients derived from the
- // same buffer in bufferhubd share the same buffer id.
- int id() const { return id_; }
-
- // Returns the current value of MetadataHeader::buffer_state.
- uint64_t buffer_state() { return metadata_header_->buffer_state.load(); }
-
- // A state mask which is unique to a buffer hub client among all its siblings
- // sharing the same concrete graphic buffer.
- uint64_t buffer_state_bit() const { return buffer_state_bit_; }
-
- // Returns true if the buffer holds an open PDX channels towards bufferhubd.
- bool IsConnected() const { return client_.IsValid(); }
-
- // Returns true if the buffer holds an valid gralloc buffer handle that's
- // availble for the client to read from and/or write into.
- bool IsValid() const { return buffer_.IsValid(); }
-
- // Returns the event mask for all the events that are pending on this buffer
- // (see sys/poll.h for all possible bits).
- pdx::Status<int> GetEventMask(int events) {
- if (auto* channel = client_.GetChannel()) {
- return channel->GetEventMask(events);
- } else {
- return pdx::ErrorStatus(EINVAL);
- }
- }
-
- // Polls the fd for |timeout_ms| milliseconds (-1 for infinity).
- int Poll(int timeout_ms);
-
- // Promotes a DetachedBuffer to become a ProducerBuffer. Once promoted the
- // DetachedBuffer channel will be closed automatically on successful IPC
- // return. Further IPCs towards this channel will return error.
- pdx::Status<pdx::LocalChannelHandle> Promote();
-
- // Creates a DetachedBuffer from an existing one.
- pdx::Status<pdx::LocalChannelHandle> Duplicate();
-
- private:
- DetachedBuffer(uint32_t width, uint32_t height, uint32_t layer_count,
- uint32_t format, uint64_t usage, size_t user_metadata_size);
-
- DetachedBuffer(pdx::LocalChannelHandle channel_handle);
-
- int ImportGraphicBuffer();
-
- // Global id for the buffer that is consistent across processes.
- int id_;
- uint64_t buffer_state_bit_;
-
- // The concrete Ion buffers.
- IonBuffer buffer_;
- IonBuffer metadata_buffer_;
-
- // buffer metadata.
- size_t user_metadata_size_ = 0;
- BufferHubDefs::MetadataHeader* metadata_header_ = nullptr;
- void* user_metadata_ptr_ = nullptr;
-
- // PDX backend.
- BufferHubClient client_;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_DETACHED_BUFFER_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
index f6bc547..860f08a 100644
--- a/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/ion_buffer.h
@@ -20,8 +20,8 @@
uint64_t usage);
~IonBuffer();
- IonBuffer(IonBuffer&& other);
- IonBuffer& operator=(IonBuffer&& other);
+ IonBuffer(IonBuffer&& other) noexcept;
+ IonBuffer& operator=(IonBuffer&& other) noexcept;
// Returns check this IonBuffer holds a valid Gralloc buffer.
bool IsValid() const { return buffer_ && buffer_->initCheck() == NO_ERROR; }
diff --git a/libs/vr/libbufferhub/include/private/dvr/native_handle_wrapper.h b/libs/vr/libbufferhub/include/private/dvr/native_handle_wrapper.h
new file mode 100644
index 0000000..3086982
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/native_handle_wrapper.h
@@ -0,0 +1,100 @@
+#ifndef ANDROID_DVR_NATIVE_HANDLE_WRAPPER_H_
+#define ANDROID_DVR_NATIVE_HANDLE_WRAPPER_H_
+
+#include <cutils/native_handle.h>
+
+#include <vector>
+
+namespace android {
+namespace dvr {
+
+// A PDX-friendly wrapper to maintain the life cycle of a native_handle_t
+// object.
+//
+// See https://source.android.com/devices/architecture/hidl/types#handle_t for
+// more information about native_handle_t.
+template <typename FileHandleType>
+class NativeHandleWrapper {
+ public:
+ NativeHandleWrapper() = default;
+ NativeHandleWrapper(NativeHandleWrapper&& other) = default;
+ NativeHandleWrapper& operator=(NativeHandleWrapper&& other) = default;
+
+ // Create a new NativeHandleWrapper by duplicating the handle.
+ explicit NativeHandleWrapper(const native_handle_t* handle) {
+ const int fd_count = handle->numFds;
+ const int int_count = handle->numInts;
+
+ // Populate the fd and int vectors: native_handle->data[] is an array of fds
+ // followed by an array of opaque ints.
+ for (int i = 0; i < fd_count; i++) {
+ fds_.emplace_back(FileHandleType::AsDuplicate(handle->data[i]));
+ }
+ for (int i = 0; i < int_count; i++) {
+ ints_.push_back(handle->data[fd_count + i]);
+ }
+ }
+
+ size_t int_count() const { return ints_.size(); }
+ size_t fd_count() const { return fds_.size(); }
+ bool IsValid() const { return ints_.size() != 0 || fds_.size() != 0; }
+
+ // Duplicate a native handle from the wrapper.
+ const native_handle_t* DuplicateHandle() const {
+ if (!IsValid()) {
+ return nullptr;
+ }
+
+ // numFds + numInts ints.
+ std::vector<FileHandleType> fds;
+ for (const auto& fd : fds_) {
+ if (!fd.IsValid()) {
+ return nullptr;
+ }
+ fds.emplace_back(fd.Duplicate());
+ }
+
+ return FromFdsAndInts(std::move(fds), ints_);
+ }
+
+ // Takes the native handle out of the wrapper.
+ const native_handle_t* TakeHandle() {
+ if (!IsValid()) {
+ return nullptr;
+ }
+
+ return FromFdsAndInts(std::move(fds_), std::move(ints_));
+ }
+
+ private:
+ NativeHandleWrapper(const NativeHandleWrapper&) = delete;
+ void operator=(const NativeHandleWrapper&) = delete;
+
+ static const native_handle_t* FromFdsAndInts(std::vector<FileHandleType> fds,
+ std::vector<int> ints) {
+ native_handle_t* handle = native_handle_create(fds.size(), ints.size());
+ if (!handle) {
+ ALOGE("NativeHandleWrapper::TakeHandle: Failed to create new handle.");
+ return nullptr;
+ }
+
+ // numFds + numInts ints.
+ for (int i = 0; i < handle->numFds; i++) {
+ handle->data[i] = fds[i].Release();
+ }
+ memcpy(&handle->data[handle->numFds], ints.data(),
+ sizeof(int) * handle->numInts);
+
+ return handle;
+ }
+
+ std::vector<int> ints_;
+ std::vector<FileHandleType> fds_;
+
+ PDX_SERIALIZABLE_MEMBERS(NativeHandleWrapper<FileHandleType>, ints_, fds_);
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_NATIVE_HANDLE_WRAPPER_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
index b5e1c5b..d2d4d1e 100644
--- a/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/producer_buffer.h
@@ -50,12 +50,6 @@
return Post(ready_fence, nullptr, 0);
}
- template <typename Meta, typename = typename std::enable_if<
- !std::is_void<Meta>::value>::type>
- int Post(const LocalHandle& ready_fence, const Meta& meta) {
- return Post(ready_fence, &meta, sizeof(meta));
- }
-
// Attempt to re-gain the buffer for writing. If |release_fence| is valid, it
// must be waited on before using the buffer. If it is not valid then the
// buffer is free for immediate use. This call will only succeed if the buffer
diff --git a/libs/vr/libbufferhub/ion_buffer.cpp b/libs/vr/libbufferhub/ion_buffer.cpp
index cbaa24a..1295531 100644
--- a/libs/vr/libbufferhub/ion_buffer.cpp
+++ b/libs/vr/libbufferhub/ion_buffer.cpp
@@ -49,11 +49,11 @@
FreeHandle();
}
-IonBuffer::IonBuffer(IonBuffer&& other) : IonBuffer() {
+IonBuffer::IonBuffer(IonBuffer&& other) noexcept : IonBuffer() {
*this = std::move(other);
}
-IonBuffer& IonBuffer::operator=(IonBuffer&& other) {
+IonBuffer& IonBuffer::operator=(IonBuffer&& other) noexcept {
ALOGD_IF(TRACE, "IonBuffer::operator=: handle_=%p other.handle_=%p", handle(),
other.handle());
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index c4f1a3b..7b6f77a 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -222,6 +222,10 @@
}
Status<LocalChannelHandle> ProducerBuffer::Detach() {
+ // TODO(b/112338294) remove after migrate producer buffer to binder
+ ALOGW("ProducerBuffer::Detach: not supported operation during migration");
+ return {};
+
uint64_t buffer_state = buffer_state_->load();
if (!BufferHubDefs::IsBufferGained(buffer_state)) {
// Can only detach a ProducerBuffer when it's in gained state.
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 9f72c05..20894e3 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -59,6 +59,9 @@
static_libs: staticLibraries,
shared_libs: sharedLibraries,
header_libs: headerLibraries,
+
+ // TODO(b/117568153): Temporarily opt out using libcrt.
+ no_libcrt: true,
}
subdirs = ["benchmarks", "tests"]
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
index 4dea9b2..ad3f56b 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_parcelable.h
@@ -28,8 +28,8 @@
public:
BufferHubQueueParcelable() = default;
- BufferHubQueueParcelable(BufferHubQueueParcelable&& other) = default;
- BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) {
+ BufferHubQueueParcelable(BufferHubQueueParcelable&& other) noexcept = default;
+ BufferHubQueueParcelable& operator=(BufferHubQueueParcelable&& other) noexcept {
channel_parcelable_ = std::move(other.channel_parcelable_);
return *this;
}
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 3260447..357dffe 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -49,6 +49,9 @@
"-g",
],
name: "dvr_api-test",
+
+ // TODO(b/117568153): Temporarily opt out using libcrt.
+ no_libcrt: true,
}
cc_test {
diff --git a/libs/vr/libdvrcommon/include/private/dvr/ring_buffer.h b/libs/vr/libdvrcommon/include/private/dvr/ring_buffer.h
index 44485a7..1824241 100644
--- a/libs/vr/libdvrcommon/include/private/dvr/ring_buffer.h
+++ b/libs/vr/libdvrcommon/include/private/dvr/ring_buffer.h
@@ -23,9 +23,9 @@
explicit RingBuffer(size_t capacity) { Reset(capacity); }
RingBuffer(const RingBuffer& other) = default;
- RingBuffer(RingBuffer&& other) = default;
+ RingBuffer(RingBuffer&& other) noexcept = default;
RingBuffer& operator=(const RingBuffer& other) = default;
- RingBuffer& operator=(RingBuffer&& other) = default;
+ RingBuffer& operator=(RingBuffer&& other) noexcept = default;
void Append(const T& val) {
if (IsFull())
diff --git a/libs/vr/libpdx/private/pdx/channel_handle.h b/libs/vr/libpdx/private/pdx/channel_handle.h
index 1e62d25..daa08f4 100644
--- a/libs/vr/libpdx/private/pdx/channel_handle.h
+++ b/libs/vr/libpdx/private/pdx/channel_handle.h
@@ -50,14 +50,14 @@
public:
ChannelHandle() = default;
using ChannelHandleBase::ChannelHandleBase;
- ChannelHandle(ChannelHandle&& other) : ChannelHandleBase{other.value_} {
+ ChannelHandle(ChannelHandle&& other) noexcept : ChannelHandleBase{other.value_} {
other.value_ = kEmptyHandle;
}
~ChannelHandle() = default;
ChannelHandle Duplicate() const { return ChannelHandle{value_}; }
- ChannelHandle& operator=(ChannelHandle&& other) {
+ ChannelHandle& operator=(ChannelHandle&& other) noexcept {
value_ = other.value_;
other.value_ = kEmptyHandle;
return *this;
@@ -74,13 +74,13 @@
ChannelHandle(const ChannelHandle&) = delete;
ChannelHandle& operator=(const ChannelHandle&) = delete;
- ChannelHandle(ChannelHandle&& other)
+ ChannelHandle(ChannelHandle&& other) noexcept
: ChannelHandleBase{other.value_}, manager_{other.manager_} {
other.manager_ = nullptr;
other.value_ = kEmptyHandle;
}
- ChannelHandle& operator=(ChannelHandle&& other) {
+ ChannelHandle& operator=(ChannelHandle&& other) noexcept {
value_ = other.value_;
manager_ = other.manager_;
other.value_ = kEmptyHandle;
diff --git a/libs/vr/libpdx/private/pdx/file_handle.h b/libs/vr/libpdx/private/pdx/file_handle.h
index b3c3ad7..fed1529 100644
--- a/libs/vr/libpdx/private/pdx/file_handle.h
+++ b/libs/vr/libpdx/private/pdx/file_handle.h
@@ -43,7 +43,7 @@
// Move constructor that assumes ownership of the file descriptor, leaving the
// other FileHandle object empty.
- FileHandle(FileHandle&& other) {
+ FileHandle(FileHandle&& other) noexcept {
fd_ = other.fd_;
other.fd_ = kEmptyFileHandle;
}
@@ -62,7 +62,7 @@
// Move assignment operator that assumes ownership of the underlying file
// descriptor, leaving the other FileHandle object empty.
- FileHandle& operator=(FileHandle&& other) {
+ FileHandle& operator=(FileHandle&& other) noexcept {
if (this != &other) {
Reset(other.fd_);
other.fd_ = kEmptyFileHandle;
diff --git a/libs/vr/libpdx/private/pdx/rpc/array_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/array_wrapper.h
index 93d87f3..d835c57 100644
--- a/libs/vr/libpdx/private/pdx/rpc/array_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/array_wrapper.h
@@ -39,7 +39,7 @@
ArrayWrapper(const ArrayWrapper& other) { *this = other; }
- ArrayWrapper(ArrayWrapper&& other) { *this = std::move(other); }
+ ArrayWrapper(ArrayWrapper&& other) noexcept { *this = std::move(other); }
ArrayWrapper& operator=(const ArrayWrapper& other) {
if (&other == this) {
@@ -53,7 +53,7 @@
return *this;
}
- ArrayWrapper& operator=(ArrayWrapper&& other) {
+ ArrayWrapper& operator=(ArrayWrapper&& other) noexcept {
if (&other == this) {
return *this;
} else {
diff --git a/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h
index aa86531..0421220 100644
--- a/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/buffer_wrapper.h
@@ -39,7 +39,7 @@
BufferWrapper(const BufferWrapper& other) { *this = other; }
- BufferWrapper(BufferWrapper&& other) { *this = std::move(other); }
+ BufferWrapper(BufferWrapper&& other) noexcept { *this = std::move(other); }
BufferWrapper& operator=(const BufferWrapper& other) {
if (&other == this) {
@@ -53,7 +53,7 @@
return *this;
}
- BufferWrapper& operator=(BufferWrapper&& other) {
+ BufferWrapper& operator=(BufferWrapper&& other) noexcept {
if (&other == this) {
return *this;
} else {
@@ -117,9 +117,9 @@
BufferWrapper(BufferType&& buffer, const Allocator& allocator)
: buffer_(std::move(buffer), allocator) {}
BufferWrapper(const BufferWrapper&) = default;
- BufferWrapper(BufferWrapper&&) = default;
+ BufferWrapper(BufferWrapper&&) noexcept = default;
BufferWrapper& operator=(const BufferWrapper&) = default;
- BufferWrapper& operator=(BufferWrapper&&) = default;
+ BufferWrapper& operator=(BufferWrapper&&) noexcept = default;
pointer data() { return buffer_.data(); }
const_pointer data() const { return buffer_.data(); }
diff --git a/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h
index d496719..1cb85de 100644
--- a/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/pointer_wrapper.h
@@ -15,9 +15,9 @@
PointerWrapper(T* pointer) : pointer_(pointer) {}
PointerWrapper(const PointerWrapper&) = default;
- PointerWrapper(PointerWrapper&&) = default;
+ PointerWrapper(PointerWrapper&&) noexcept = default;
PointerWrapper& operator=(const PointerWrapper&) = default;
- PointerWrapper& operator=(PointerWrapper&&) = default;
+ PointerWrapper& operator=(PointerWrapper&&) noexcept = default;
T& Dereference() { return *pointer_; }
const T& Dereference() const { return *pointer_; }
diff --git a/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h b/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h
index 19fc4c1..2d0a4ea 100644
--- a/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h
+++ b/libs/vr/libpdx/private/pdx/rpc/string_wrapper.h
@@ -44,7 +44,7 @@
StringWrapper(const StringWrapper& other) { *this = other; }
- StringWrapper(StringWrapper&& other) { *this = std::move(other); }
+ StringWrapper(StringWrapper&& other) noexcept { *this = std::move(other); }
StringWrapper& operator=(const StringWrapper& other) {
if (&other == this) {
@@ -58,7 +58,7 @@
return *this;
}
- StringWrapper& operator=(StringWrapper&& other) {
+ StringWrapper& operator=(StringWrapper&& other) noexcept {
if (&other == this) {
return *this;
} else {
diff --git a/libs/vr/libpdx/private/pdx/rpc/variant.h b/libs/vr/libpdx/private/pdx/rpc/variant.h
index 0a4802e..a1292b0 100644
--- a/libs/vr/libpdx/private/pdx/rpc/variant.h
+++ b/libs/vr/libpdx/private/pdx/rpc/variant.h
@@ -447,7 +447,7 @@
Variant(const Variant& other)
: index_{other.index_}, value_{other.value_, other.index_} {}
- Variant(Variant&& other)
+ Variant(Variant&& other) noexcept
: index_{other.index_}, value_{std::move(other.value_), other.index_} {}
// Recent Clang versions has a regression that produces bogus
@@ -472,7 +472,7 @@
other.Visit([this](const auto& value) { *this = value; });
return *this;
}
- Variant& operator=(Variant&& other) {
+ Variant& operator=(Variant&& other) noexcept {
other.Visit([this](auto&& value) { *this = std::move(value); });
return *this;
}
diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h
index 15fa327..d38b174 100644
--- a/libs/vr/libpdx/private/pdx/service.h
+++ b/libs/vr/libpdx/private/pdx/service.h
@@ -101,8 +101,8 @@
/*
* Message objects support move construction and assignment.
*/
- Message(Message&& other);
- Message& operator=(Message&& other);
+ Message(Message&& other) noexcept;
+ Message& operator=(Message&& other) noexcept;
/*
* Read/write payload, in either single buffer or iovec form.
diff --git a/libs/vr/libpdx/private/pdx/status.h b/libs/vr/libpdx/private/pdx/status.h
index 067fe25..7e51a52 100644
--- a/libs/vr/libpdx/private/pdx/status.h
+++ b/libs/vr/libpdx/private/pdx/status.h
@@ -41,14 +41,14 @@
// Copy/move constructors. Move constructor leaves |other| object in empty
// state.
Status(const Status& other) = default;
- Status(Status&& other)
+ Status(Status&& other) noexcept
: value_{std::move(other.value_)}, error_{other.error_} {
other.error_ = -1;
}
// Assignment operators.
Status& operator=(const Status& other) = default;
- Status& operator=(Status&& other) {
+ Status& operator=(Status&& other) noexcept {
error_ = other.error_;
value_ = std::move(other.value_);
other.error_ = -1;
diff --git a/libs/vr/libpdx/private/pdx/utility.h b/libs/vr/libpdx/private/pdx/utility.h
index 08fcaea..c9a0c21 100644
--- a/libs/vr/libpdx/private/pdx/utility.h
+++ b/libs/vr/libpdx/private/pdx/utility.h
@@ -33,7 +33,7 @@
return *this;
}
- ByteBuffer& operator=(ByteBuffer&& other) {
+ ByteBuffer& operator=(ByteBuffer&& other) noexcept {
std::swap(data_, other.data_);
std::swap(size_, other.size_);
std::swap(capacity_, other.capacity_);
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index 1d3b62a..68b8dd7 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -31,9 +31,9 @@
// C++11 specifies the move semantics for shared_ptr but not weak_ptr. This
// means we have to manually implement the desired move semantics for Message.
-Message::Message(Message&& other) { *this = std::move(other); }
+Message::Message(Message&& other) noexcept { *this = std::move(other); }
-Message& Message::operator=(Message&& other) {
+Message& Message::operator=(Message&& other) noexcept {
Destroy();
auto base = reinterpret_cast<std::uint8_t*>(&info_);
std::fill(&base[0], &base[sizeof(info_)], 0);
diff --git a/libs/vr/libvrflinger/acquired_buffer.cpp b/libs/vr/libvrflinger/acquired_buffer.cpp
index 9614c6d..5d873d1 100644
--- a/libs/vr/libvrflinger/acquired_buffer.cpp
+++ b/libs/vr/libvrflinger/acquired_buffer.cpp
@@ -31,13 +31,13 @@
}
}
-AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other) {
+AcquiredBuffer::AcquiredBuffer(AcquiredBuffer&& other) noexcept {
*this = std::move(other);
}
AcquiredBuffer::~AcquiredBuffer() { Release(LocalHandle(kEmptyFence)); }
-AcquiredBuffer& AcquiredBuffer::operator=(AcquiredBuffer&& other) {
+AcquiredBuffer& AcquiredBuffer::operator=(AcquiredBuffer&& other) noexcept {
if (this != &other) {
Release();
diff --git a/libs/vr/libvrflinger/acquired_buffer.h b/libs/vr/libvrflinger/acquired_buffer.h
index 32e912a..1a200aa 100644
--- a/libs/vr/libvrflinger/acquired_buffer.h
+++ b/libs/vr/libvrflinger/acquired_buffer.h
@@ -31,7 +31,7 @@
AcquiredBuffer(const std::shared_ptr<BufferConsumer>& buffer, int* error);
// Move constructor. Behaves similarly to the move assignment operator below.
- AcquiredBuffer(AcquiredBuffer&& other);
+ AcquiredBuffer(AcquiredBuffer&& other) noexcept;
~AcquiredBuffer();
@@ -39,7 +39,7 @@
// |other| into this instance after RELEASING the current BufferConsumer and
// closing the acquire fence. After the move |other| is left in the empty
// state.
- AcquiredBuffer& operator=(AcquiredBuffer&& other);
+ AcquiredBuffer& operator=(AcquiredBuffer&& other) noexcept;
// Accessors for the underlying BufferConsumer, the acquire fence, and the
// use-case specific sequence value from the acquisition (see
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index e98d592..5f6455c 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -1338,9 +1338,9 @@
Layer::~Layer() { Reset(); }
-Layer::Layer(Layer&& other) { *this = std::move(other); }
+Layer::Layer(Layer&& other) noexcept { *this = std::move(other); }
-Layer& Layer::operator=(Layer&& other) {
+Layer& Layer::operator=(Layer&& other) noexcept {
if (this != &other) {
Reset();
using std::swap;
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 80fa7ac..94a2337 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -87,8 +87,8 @@
const std::shared_ptr<IonBuffer>& buffer, HWC::BlendMode blending,
HWC::Composition composition_type, size_t z_order);
- Layer(Layer&&);
- Layer& operator=(Layer&&);
+ Layer(Layer&&) noexcept;
+ Layer& operator=(Layer&&) noexcept;
~Layer();
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.cpp b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
index e1c7adb..1d5740f 100644
--- a/libs/vr/libvrflinger/tests/vrflinger_test.cpp
+++ b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
@@ -218,10 +218,7 @@
ASSERT_GE(buffer.get()->Unlock(), 0);
- ASSERT_GE(buffer.get()->Post(/*ready_fence=*/pdx::LocalHandle(),
- /*meta=*/nullptr,
- /*user_metadata_size=*/0),
- 0);
+ ASSERT_GE(buffer.get()->Post(/*ready_fence=*/pdx::LocalHandle()), 0);
ASSERT_EQ(
surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/true),
diff --git a/libs/vr/libvrsensor/pose_client.cpp b/libs/vr/libvrsensor/pose_client.cpp
index 4acc085..710d75a 100644
--- a/libs/vr/libvrsensor/pose_client.cpp
+++ b/libs/vr/libvrsensor/pose_client.cpp
@@ -228,7 +228,7 @@
}
constexpr size_t size = DvrVsyncPoseBuffer::kSize * sizeof(DvrPoseAsync);
void* addr = nullptr;
- int ret = buffer->GetBlobReadOnlyPointer(size, &addr);
+ int ret = buffer->GetBlobReadWritePointer(size, &addr);
if (ret < 0 || !addr) {
ALOGE("Pose failed to map ring buffer: ret:%d, addr:%p", ret, addr);
return -EIO;
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 1421a48..87f0fe1 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -273,6 +273,7 @@
void Loader::init_api(void* dso,
char const * const * api,
+ char const * const * ref_api,
__eglMustCastToProperFunctionPointerType* curr,
getProcAddressType getProcAddress)
{
@@ -282,6 +283,15 @@
char scrap[SIZE];
while (*api) {
char const * name = *api;
+ if (ref_api) {
+ char const * ref_name = *ref_api;
+ if (std::strcmp(name, ref_name) != 0) {
+ *curr++ = nullptr;
+ ref_api++;
+ continue;
+ }
+ }
+
__eglMustCastToProperFunctionPointerType f =
(__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
if (f == nullptr) {
@@ -326,6 +336,7 @@
}
*curr++ = f;
api++;
+ if (ref_api) ref_api++;
}
}
@@ -529,7 +540,7 @@
property_get("ro.product.model", model, "UNSET");
ANGLEPreference app_preference = getAnglePref(android_getAngleAppPref());
- so = load_angle_from_namespace("GLESv2", ns);
+ so = load_angle_from_namespace("feature_support", ns);
if (so) {
ALOGV("Temporarily loaded ANGLE's opt-in/out logic from namespace");
fpANGLEUseForApplication fp =
@@ -538,6 +549,8 @@
use_angle = (fp)(app_name_str.c_str(), manufacturer, model, developer_option,
app_preference);
ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
+ } else {
+ ALOGW("Cannot find ANGLEUseForApplication in library");
}
ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
@@ -648,14 +661,14 @@
}
if (mask & GLESv1_CM) {
- init_api(dso, gl_names,
+ init_api(dso, gl_names_1, gl_names,
(__eglMustCastToProperFunctionPointerType*)
&cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl,
getProcAddress);
}
if (mask & GLESv2) {
- init_api(dso, gl_names,
+ init_api(dso, gl_names, nullptr,
(__eglMustCastToProperFunctionPointerType*)
&cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,
getProcAddress);
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 6a32bb3..e88d1a2 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -29,7 +29,7 @@
class Loader {
typedef __eglMustCastToProperFunctionPointerType (* getProcAddressType)(const char*);
-
+
enum {
EGL = 0x01,
GLESv1_CM = 0x02,
@@ -42,25 +42,26 @@
int set(void* hnd, int32_t api);
void* dso[3];
};
-
+
getProcAddressType getProcAddress;
public:
static Loader& getInstance();
~Loader();
-
+
void* open(egl_connection_t* cnx);
void close(void* driver);
-
+
private:
Loader();
void *load_driver(const char* kind, egl_connection_t* cnx, uint32_t mask);
static __attribute__((noinline))
- void init_api(void* dso,
- char const * const * api,
- __eglMustCastToProperFunctionPointerType* curr,
- getProcAddressType getProcAddress);
+ void init_api(void* dso,
+ char const * const * api,
+ char const * const * ref_api,
+ __eglMustCastToProperFunctionPointerType* curr,
+ getProcAddressType getProcAddress);
};
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index e292b80..7089860 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -252,6 +252,11 @@
nullptr
};
+char const * const gl_names_1[] = {
+ #include "../entries_gles1.in"
+ nullptr
+};
+
char const * const egl_names[] = {
#include "egl_entries.in"
nullptr
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 1ed9850..d2dc514 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -562,6 +562,15 @@
break;
}
}
+
+ // If the driver doesn't understand it, we should map sRGB-encoded P3 to
+ // sRGB rather than just dropping the colorspace on the floor.
+ // For this format, the driver is expected to apply the sRGB
+ // transfer function during framebuffer operations.
+ if (!copyAttribute && attr[1] == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) {
+ strippedAttribList->push_back(attr[0]);
+ strippedAttribList->push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+ }
}
if (copyAttribute) {
strippedAttribList->push_back(attr[0]);
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 4990af6..449ffc7 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -62,6 +62,7 @@
extern "C" void gl_noop();
extern char const * const gl_names[];
+extern char const * const gl_names_1[];
extern char const * const egl_names[];
extern egl_connection_t gEGLImpl;
diff --git a/opengl/libs/entries_gles1.in b/opengl/libs/entries_gles1.in
new file mode 100644
index 0000000..c9be593
--- /dev/null
+++ b/opengl/libs/entries_gles1.in
@@ -0,0 +1,298 @@
+GL_ENTRY(void, glActiveTexture, GLenum texture)
+GL_ENTRY(void, glAlphaFunc, GLenum func, GLfloat ref)
+GL_ENTRY(void, glAlphaFuncx, GLenum func, GLfixed ref)
+GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLfixed ref)
+GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)
+GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer)
+GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture)
+GL_ENTRY(void, glBindVertexArrayOES, GLuint array)
+GL_ENTRY(void, glBlendEquationOES, GLenum mode)
+GL_ENTRY(void, glBlendEquationSeparateOES, GLenum modeRGB, GLenum modeAlpha)
+GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
+GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const void *data, GLenum usage)
+GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const void *data)
+GL_ENTRY(GLenum, glCheckFramebufferStatusOES, GLenum target)
+GL_ENTRY(void, glClear, GLbitfield mask)
+GL_ENTRY(void, glClearColor, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+GL_ENTRY(void, glClearColorx, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glClearColorxOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glClearDepthf, GLfloat d)
+GL_ENTRY(void, glClearDepthfOES, GLclampf depth)
+GL_ENTRY(void, glClearDepthx, GLfixed depth)
+GL_ENTRY(void, glClearDepthxOES, GLfixed depth)
+GL_ENTRY(void, glClearStencil, GLint s)
+GL_ENTRY(void, glClientActiveTexture, GLenum texture)
+GL_ENTRY(GLenum, glClientWaitSyncAPPLE, GLsync sync, GLbitfield flags, GLuint64 timeout)
+GL_ENTRY(void, glClipPlanef, GLenum p, const GLfloat *eqn)
+GL_ENTRY(void, glClipPlanefIMG, GLenum p, const GLfloat *eqn)
+GL_ENTRY(void, glClipPlanefOES, GLenum plane, const GLfloat *equation)
+GL_ENTRY(void, glClipPlanex, GLenum plane, const GLfixed *equation)
+GL_ENTRY(void, glClipPlanexIMG, GLenum p, const GLfixed *eqn)
+GL_ENTRY(void, glClipPlanexOES, GLenum plane, const GLfixed *equation)
+GL_ENTRY(void, glColor4f, GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+GL_ENTRY(void, glColor4ub, GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)
+GL_ENTRY(void, glColor4x, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glColor4xOES, GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+GL_ENTRY(void, glColorMask, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+GL_ENTRY(void, glColorPointer, GLint size, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glCompressedTexImage2D, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data)
+GL_ENTRY(void, glCompressedTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data)
+GL_ENTRY(void, glCopyTexImage2D, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+GL_ENTRY(void, glCopyTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glCopyTextureLevelsAPPLE, GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount)
+GL_ENTRY(void, glCullFace, GLenum mode)
+GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex)
+GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers)
+GL_ENTRY(void, glDeleteFencesNV, GLsizei n, const GLuint *fences)
+GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint *framebuffers)
+GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint *renderbuffers)
+GL_ENTRY(void, glDeleteSyncAPPLE, GLsync sync)
+GL_ENTRY(void, glDeleteTextures, GLsizei n, const GLuint *textures)
+GL_ENTRY(void, glDeleteVertexArraysOES, GLsizei n, const GLuint *arrays)
+GL_ENTRY(void, glDepthFunc, GLenum func)
+GL_ENTRY(void, glDepthMask, GLboolean flag)
+GL_ENTRY(void, glDepthRangef, GLfloat n, GLfloat f)
+GL_ENTRY(void, glDepthRangefOES, GLclampf n, GLclampf f)
+GL_ENTRY(void, glDepthRangex, GLfixed n, GLfixed f)
+GL_ENTRY(void, glDepthRangexOES, GLfixed n, GLfixed f)
+GL_ENTRY(void, glDisable, GLenum cap)
+GL_ENTRY(void, glDisableClientState, GLenum array)
+GL_ENTRY(void, glDisableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments)
+GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)
+GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const void *indices)
+GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height)
+GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords)
+GL_ENTRY(void, glDrawTexiOES, GLint x, GLint y, GLint z, GLint width, GLint height)
+GL_ENTRY(void, glDrawTexivOES, const GLint *coords)
+GL_ENTRY(void, glDrawTexsOES, GLshort x, GLshort y, GLshort z, GLshort width, GLshort height)
+GL_ENTRY(void, glDrawTexsvOES, const GLshort *coords)
+GL_ENTRY(void, glDrawTexxOES, GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height)
+GL_ENTRY(void, glDrawTexxvOES, const GLfixed *coords)
+GL_ENTRY(void, glEGLImageTargetRenderbufferStorageOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEGLImageTargetTexture2DOES, GLenum target, GLeglImageOES image)
+GL_ENTRY(void, glEnable, GLenum cap)
+GL_ENTRY(void, glEnableClientState, GLenum array)
+GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl)
+GL_ENTRY(void, glEndTilingQCOM, GLbitfield preserveMask)
+GL_ENTRY(void, glExtGetBufferPointervQCOM, GLenum target, void **params)
+GL_ENTRY(void, glExtGetBuffersQCOM, GLuint *buffers, GLint maxBuffers, GLint *numBuffers)
+GL_ENTRY(void, glExtGetFramebuffersQCOM, GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers)
+GL_ENTRY(void, glExtGetProgramBinarySourceQCOM, GLuint program, GLenum shadertype, GLchar *source, GLint *length)
+GL_ENTRY(void, glExtGetProgramsQCOM, GLuint *programs, GLint maxPrograms, GLint *numPrograms)
+GL_ENTRY(void, glExtGetRenderbuffersQCOM, GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers)
+GL_ENTRY(void, glExtGetShadersQCOM, GLuint *shaders, GLint maxShaders, GLint *numShaders)
+GL_ENTRY(void, glExtGetTexLevelParameterivQCOM, GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params)
+GL_ENTRY(void, glExtGetTexSubImageQCOM, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, void *texels)
+GL_ENTRY(void, glExtGetTexturesQCOM, GLuint *textures, GLint maxTextures, GLint *numTextures)
+GL_ENTRY(GLboolean, glExtIsProgramBinaryQCOM, GLuint program)
+GL_ENTRY(void, glExtTexObjectStateOverrideiQCOM, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(GLsync, glFenceSyncAPPLE, GLenum condition, GLbitfield flags)
+GL_ENTRY(void, glFinish, void)
+GL_ENTRY(void, glFinishFenceNV, GLuint fence)
+GL_ENTRY(void, glFlush, void)
+GL_ENTRY(void, glFlushMappedBufferRangeEXT, GLenum target, GLintptr offset, GLsizeiptr length)
+GL_ENTRY(void, glFogf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glFogfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glFogx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glFogxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glFogxv, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glFogxvOES, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+GL_ENTRY(void, glFramebufferTexture2DMultisampleEXT, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
+GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
+GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glFrontFace, GLenum mode)
+GL_ENTRY(void, glFrustumf, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f)
+GL_ENTRY(void, glFrustumfOES, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f)
+GL_ENTRY(void, glFrustumx, GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f)
+GL_ENTRY(void, glFrustumxOES, GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f)
+GL_ENTRY(void, glGenBuffers, GLsizei n, GLuint *buffers)
+GL_ENTRY(void, glGenFencesNV, GLsizei n, GLuint *fences)
+GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint *framebuffers)
+GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint *renderbuffers)
+GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures)
+GL_ENTRY(void, glGenVertexArraysOES, GLsizei n, GLuint *arrays)
+GL_ENTRY(void, glGenerateMipmapOES, GLenum target)
+GL_ENTRY(void, glGetBooleanv, GLenum pname, GLboolean *data)
+GL_ENTRY(void, glGetBufferParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetBufferPointervOES, GLenum target, GLenum pname, void **params)
+GL_ENTRY(void, glGetClipPlanef, GLenum plane, GLfloat *equation)
+GL_ENTRY(void, glGetClipPlanefOES, GLenum plane, GLfloat *equation)
+GL_ENTRY(void, glGetClipPlanex, GLenum plane, GLfixed *equation)
+GL_ENTRY(void, glGetClipPlanexOES, GLenum plane, GLfixed *equation)
+GL_ENTRY(void, glGetDriverControlStringQCOM, GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString)
+GL_ENTRY(void, glGetDriverControlsQCOM, GLint *num, GLsizei size, GLuint *driverControls)
+GL_ENTRY(GLenum, glGetError, void)
+GL_ENTRY(void, glGetFenceivNV, GLuint fence, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetFixedv, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetFixedvOES, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *data)
+GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint *params)
+GL_ENTRY(GLenum, glGetGraphicsResetStatusEXT, void)
+GL_ENTRY(void, glGetInteger64vAPPLE, GLenum pname, GLint64 *params)
+GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *data)
+GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetLightxvOES, GLenum light, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetPointerv, GLenum pname, void **params)
+GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(const GLubyte *, glGetString, GLenum name)
+GL_ENTRY(void, glGetSyncivAPPLE, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)
+GL_ENTRY(void, glGetTexEnvfv, GLenum target, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexEnviv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexEnvxv, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexEnvxvOES, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexGenfvOES, GLenum coord, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexGenivOES, GLenum coord, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexGenxvOES, GLenum coord, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexParameterfv, GLenum target, GLenum pname, GLfloat *params)
+GL_ENTRY(void, glGetTexParameteriv, GLenum target, GLenum pname, GLint *params)
+GL_ENTRY(void, glGetTexParameterxv, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetTexParameterxvOES, GLenum target, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetnUniformfvEXT, GLuint program, GLint location, GLsizei bufSize, GLfloat *params)
+GL_ENTRY(void, glGetnUniformivEXT, GLuint program, GLint location, GLsizei bufSize, GLint *params)
+GL_ENTRY(void, glHint, GLenum target, GLenum mode)
+GL_ENTRY(void, glInsertEventMarkerEXT, GLsizei length, const GLchar *marker)
+GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer)
+GL_ENTRY(GLboolean, glIsEnabled, GLenum cap)
+GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence)
+GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer)
+GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer)
+GL_ENTRY(GLboolean, glIsSyncAPPLE, GLsync sync)
+GL_ENTRY(GLboolean, glIsTexture, GLuint texture)
+GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array)
+GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightModelxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightModelxv, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glLightModelxvOES, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glLightf, GLenum light, GLenum pname, GLfloat param)
+GL_ENTRY(void, glLightfv, GLenum light, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glLightx, GLenum light, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightxOES, GLenum light, GLenum pname, GLfixed param)
+GL_ENTRY(void, glLightxv, GLenum light, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLightxvOES, GLenum light, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glLineWidth, GLfloat width)
+GL_ENTRY(void, glLineWidthx, GLfixed width)
+GL_ENTRY(void, glLineWidthxOES, GLfixed width)
+GL_ENTRY(void, glLoadIdentity, void)
+GL_ENTRY(void, glLoadMatrixf, const GLfloat *m)
+GL_ENTRY(void, glLoadMatrixx, const GLfixed *m)
+GL_ENTRY(void, glLoadMatrixxOES, const GLfixed *m)
+GL_ENTRY(void, glLoadPaletteFromModelViewMatrixOES, void)
+GL_ENTRY(void, glLogicOp, GLenum opcode)
+GL_ENTRY(void *, glMapBufferOES, GLenum target, GLenum access)
+GL_ENTRY(void *, glMapBufferRangeEXT, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
+GL_ENTRY(void, glMaterialf, GLenum face, GLenum pname, GLfloat param)
+GL_ENTRY(void, glMaterialfv, GLenum face, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glMaterialx, GLenum face, GLenum pname, GLfixed param)
+GL_ENTRY(void, glMaterialxOES, GLenum face, GLenum pname, GLfixed param)
+GL_ENTRY(void, glMaterialxv, GLenum face, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glMaterialxvOES, GLenum face, GLenum pname, const GLfixed *param)
+GL_ENTRY(void, glMatrixIndexPointerOES, GLint size, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glMatrixMode, GLenum mode)
+GL_ENTRY(void, glMultMatrixf, const GLfloat *m)
+GL_ENTRY(void, glMultMatrixx, const GLfixed *m)
+GL_ENTRY(void, glMultMatrixxOES, const GLfixed *m)
+GL_ENTRY(void, glMultiDrawArraysEXT, GLenum mode, const GLint *first, const GLsizei *count, GLsizei primcount)
+GL_ENTRY(void, glMultiDrawElementsEXT, GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount)
+GL_ENTRY(void, glMultiTexCoord4f, GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+GL_ENTRY(void, glMultiTexCoord4x, GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glMultiTexCoord4xOES, GLenum texture, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+GL_ENTRY(void, glNormal3f, GLfloat nx, GLfloat ny, GLfloat nz)
+GL_ENTRY(void, glNormal3x, GLfixed nx, GLfixed ny, GLfixed nz)
+GL_ENTRY(void, glNormal3xOES, GLfixed nx, GLfixed ny, GLfixed nz)
+GL_ENTRY(void, glNormalPointer, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glOrthof, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f)
+GL_ENTRY(void, glOrthofOES, GLfloat l, GLfloat r, GLfloat b, GLfloat t, GLfloat n, GLfloat f)
+GL_ENTRY(void, glOrthox, GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f)
+GL_ENTRY(void, glOrthoxOES, GLfixed l, GLfixed r, GLfixed b, GLfixed t, GLfixed n, GLfixed f)
+GL_ENTRY(void, glPixelStorei, GLenum pname, GLint param)
+GL_ENTRY(void, glPointParameterf, GLenum pname, GLfloat param)
+GL_ENTRY(void, glPointParameterfv, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glPointParameterx, GLenum pname, GLfixed param)
+GL_ENTRY(void, glPointParameterxOES, GLenum pname, GLfixed param)
+GL_ENTRY(void, glPointParameterxv, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glPointParameterxvOES, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glPointSize, GLfloat size)
+GL_ENTRY(void, glPointSizePointerOES, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glPointSizex, GLfixed size)
+GL_ENTRY(void, glPointSizexOES, GLfixed size)
+GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
+GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glPopGroupMarkerEXT, void)
+GL_ENTRY(void, glPopMatrix, void)
+GL_ENTRY(void, glPushGroupMarkerEXT, GLsizei length, const GLchar *marker)
+GL_ENTRY(void, glPushMatrix, void)
+GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed *mantissa, GLint *exponent)
+GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels)
+GL_ENTRY(void, glReadnPixelsEXT, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data)
+GL_ENTRY(void, glRenderbufferStorageMultisampleAPPLE, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageMultisampleEXT, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageMultisampleIMG, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glResolveMultisampleFramebufferAPPLE, void)
+GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glSampleCoverage, GLfloat value, GLboolean invert)
+GL_ENTRY(void, glSampleCoveragex, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glSampleCoveragexOES, GLclampx value, GLboolean invert)
+GL_ENTRY(void, glScalef, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glScalex, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glScalexOES, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glScissor, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glSetFenceNV, GLuint fence, GLenum condition)
+GL_ENTRY(void, glShadeModel, GLenum mode)
+GL_ENTRY(void, glStartTilingQCOM, GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask)
+GL_ENTRY(void, glStencilFunc, GLenum func, GLint ref, GLuint mask)
+GL_ENTRY(void, glStencilMask, GLuint mask)
+GL_ENTRY(void, glStencilOp, GLenum fail, GLenum zfail, GLenum zpass)
+GL_ENTRY(GLboolean, glTestFenceNV, GLuint fence)
+GL_ENTRY(void, glTexCoordPointer, GLint size, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glTexEnvf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexEnvfv, GLenum target, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexEnvi, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexEnviv, GLenum target, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexEnvx, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexEnvxOES, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexEnvxv, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexEnvxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexGenfOES, GLenum coord, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexGenfvOES, GLenum coord, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexGeniOES, GLenum coord, GLenum pname, GLint param)
+GL_ENTRY(void, glTexGenivOES, GLenum coord, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexGenxOES, GLenum coord, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexGenxvOES, GLenum coord, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexImage2D, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels)
+GL_ENTRY(void, glTexParameterf, GLenum target, GLenum pname, GLfloat param)
+GL_ENTRY(void, glTexParameterfv, GLenum target, GLenum pname, const GLfloat *params)
+GL_ENTRY(void, glTexParameteri, GLenum target, GLenum pname, GLint param)
+GL_ENTRY(void, glTexParameteriv, GLenum target, GLenum pname, const GLint *params)
+GL_ENTRY(void, glTexParameterx, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param)
+GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexStorage1DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width)
+GL_ENTRY(void, glTexStorage2DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glTexStorage3DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
+GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels)
+GL_ENTRY(void, glTextureStorage1DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width)
+GL_ENTRY(void, glTextureStorage2DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glTextureStorage3DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
+GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z)
+GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target)
+GL_ENTRY(void, glVertexPointer, GLint size, GLenum type, GLsizei stride, const void *pointer)
+GL_ENTRY(void, glViewport, GLint x, GLint y, GLsizei width, GLsizei height)
+GL_ENTRY(void, glWaitSyncAPPLE, GLsync sync, GLbitfield flags, GLuint64 timeout)
+GL_ENTRY(void, glWeightPointerOES, GLint size, GLenum type, GLsizei stride, const void *pointer)
diff --git a/opengl/tools/glgen2/glgen.py b/opengl/tools/glgen2/glgen.py
index fa981a8..86fa28f 100755
--- a/opengl/tools/glgen2/glgen.py
+++ b/opengl/tools/glgen2/glgen.py
@@ -250,6 +250,27 @@
for opts in TRAMPOLINE_OPTIONS:
registry.apiGen(opts)
+ # Generate a GLESv1_CM entries separately to avoid extra driver loading time
+ apigen = ApiGenerator()
+ registry.setGenerator(apigen)
+ API_OPTIONS = [
+ # Generate non-extension versions of each API first, then extensions,
+ # so that if an extension enum was later standardized, we see the non-
+ # suffixed version first.
+ reg.GeneratorOptions(
+ apiname = 'gles1',
+ profile = 'common'),
+ reg.GeneratorOptions(
+ apiname = 'gles1',
+ profile = 'common',
+ emitversions = None,
+ defaultExtensions = 'gles1')]
+ for opts in API_OPTIONS:
+ registry.apiGen(opts)
+ apigen.finish()
+ with open('../../libs/entries_gles1.in', 'w') as f:
+ apigen.writeEntries(f)
+
apigen = ApiGenerator()
registry.setGenerator(apigen)
API_OPTIONS = [
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 45efb9f..9a65452 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -19,12 +19,10 @@
srcs: [
"EventHub.cpp",
- "InputApplication.cpp",
"InputDispatcher.cpp",
"InputListener.cpp",
"InputManager.cpp",
"InputReader.cpp",
- "InputWindow.cpp",
],
shared_libs: [
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index d609573..38104c4 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -235,6 +235,12 @@
}
}
+template<typename T, typename U>
+static T getValueByKey(std::unordered_map<U, T>& map, U key) {
+ typename std::unordered_map<U, T>::const_iterator it = map.find(key);
+ return it != map.end() ? it->second : T{};
+}
+
// --- InputDispatcher ---
@@ -244,6 +250,7 @@
mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(nullptr),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
+ mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
mLooper = new Looper(false);
@@ -808,8 +815,10 @@
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
- if (mFocusedWindowHandle != nullptr) {
- commandEntry->inputWindowHandle = mFocusedWindowHandle;
+ sp<InputWindowHandle> focusedWindowHandle =
+ getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
+ if (focusedWindowHandle != nullptr) {
+ commandEntry->inputWindowHandle = focusedWindowHandle;
}
commandEntry->keyEntry = entry;
entry->refCount += 1;
@@ -1108,17 +1117,49 @@
mInputTargetWaitApplicationHandle.clear();
}
+/**
+ * Get the display id that the given event should go to. If this event specifies a valid display id,
+ * then it should be dispatched to that display. Otherwise, the event goes to the focused display.
+ * Focused display is the display that the user most recently interacted with.
+ */
+int32_t InputDispatcher::getTargetDisplayId(const EventEntry* entry) {
+ int32_t displayId;
+ switch (entry->type) {
+ case EventEntry::TYPE_KEY: {
+ const KeyEntry* typedEntry = static_cast<const KeyEntry*>(entry);
+ displayId = typedEntry->displayId;
+ break;
+ }
+ case EventEntry::TYPE_MOTION: {
+ const MotionEntry* typedEntry = static_cast<const MotionEntry*>(entry);
+ displayId = typedEntry->displayId;
+ break;
+ }
+ default: {
+ ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry->type);
+ return ADISPLAY_ID_NONE;
+ }
+ }
+ return displayId == ADISPLAY_ID_NONE ? mFocusedDisplayId : displayId;
+}
+
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
int32_t injectionResult;
std::string reason;
+ int32_t displayId = getTargetDisplayId(entry);
+ sp<InputWindowHandle> focusedWindowHandle =
+ getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+ sp<InputApplicationHandle> focusedApplicationHandle =
+ getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
+
// If there is no currently focused window and no focused application
// then drop the event.
- if (mFocusedWindowHandle == nullptr) {
- if (mFocusedApplicationHandle != nullptr) {
+ if (focusedWindowHandle == nullptr) {
+ if (focusedApplicationHandle != nullptr) {
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplicationHandle, nullptr, nextWakeupTime,
+ focusedApplicationHandle, nullptr, nextWakeupTime,
"Waiting because no window has focus but there is a "
"focused application that may eventually add a window "
"when it finishes starting up.");
@@ -1131,23 +1172,23 @@
}
// Check permissions.
- if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
+ if (!checkInjectionPermission(focusedWindowHandle, entry->injectionState)) {
injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
goto Failed;
}
// Check whether the window is ready for more input.
reason = checkWindowReadyForMoreInputLocked(currentTime,
- mFocusedWindowHandle, entry, "focused");
+ focusedWindowHandle, entry, "focused");
if (!reason.empty()) {
injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
- mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.c_str());
+ focusedApplicationHandle, focusedWindowHandle, nextWakeupTime, reason.c_str());
goto Unresponsive;
}
// Success! Output targets.
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
- addWindowTargetLocked(mFocusedWindowHandle,
+ addWindowTargetLocked(focusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
inputTargets);
@@ -1802,8 +1843,11 @@
}
void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
- if (mFocusedWindowHandle != nullptr) {
- const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
+ int32_t displayId = getTargetDisplayId(eventEntry);
+ sp<InputWindowHandle> focusedWindowHandle =
+ getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+ if (focusedWindowHandle != nullptr) {
+ const InputWindowInfo* info = focusedWindowHandle->getInfo();
if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());
@@ -2978,18 +3022,7 @@
// Copy old handles for release if they are no longer present.
const Vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
- // TODO(b/111361570): multi-display focus, one focus window per display.
- sp<InputWindowHandle> newFocusedWindowHandle = mFocusedWindowHandle;
- // Reset newFocusedWindowHandle to nullptr if current display own the focus window,
- // that will be updated below when going through all window handles in current display.
- // And if list of window handles becomes empty then it will be updated by other display.
- if (mFocusedWindowHandle != nullptr) {
- const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
- if (info == nullptr || info->displayId == displayId) {
- newFocusedWindowHandle = nullptr;
- }
- }
-
+ sp<InputWindowHandle> newFocusedWindowHandle = nullptr;
bool foundHoveredWindow = false;
if (inputWindowHandles.isEmpty()) {
@@ -3026,28 +3059,31 @@
mLastHoverWindowHandle = nullptr;
}
- // TODO(b/111361570): multi-display focus, one focus in all display in current.
- if (mFocusedWindowHandle != newFocusedWindowHandle) {
- if (mFocusedWindowHandle != nullptr) {
+ sp<InputWindowHandle> oldFocusedWindowHandle =
+ getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+
+ if (oldFocusedWindowHandle != newFocusedWindowHandle) {
+ if (oldFocusedWindowHandle != nullptr) {
#if DEBUG_FOCUS
ALOGD("Focus left window: %s",
- mFocusedWindowHandle->getName().c_str());
+ oldFocusedWindowHandle->getName().c_str());
#endif
- sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel();
+ sp<InputChannel> focusedInputChannel = oldFocusedWindowHandle->getInputChannel();
if (focusedInputChannel != nullptr) {
CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"focus left window");
synthesizeCancelationEventsForInputChannelLocked(
focusedInputChannel, options);
}
+ mFocusedWindowHandlesByDisplay.erase(displayId);
}
if (newFocusedWindowHandle != nullptr) {
#if DEBUG_FOCUS
ALOGD("Focus entered window: %s",
newFocusedWindowHandle->getName().c_str());
#endif
+ mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle;
}
- mFocusedWindowHandle = newFocusedWindowHandle;
}
ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
@@ -3096,25 +3132,28 @@
}
void InputDispatcher::setFocusedApplication(
- const sp<InputApplicationHandle>& inputApplicationHandle) {
+ int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) {
#if DEBUG_FOCUS
ALOGD("setFocusedApplication");
#endif
{ // acquire lock
AutoMutex _l(mLock);
+ sp<InputApplicationHandle> oldFocusedApplicationHandle =
+ getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
if (inputApplicationHandle != nullptr && inputApplicationHandle->updateInfo()) {
- if (mFocusedApplicationHandle != inputApplicationHandle) {
- if (mFocusedApplicationHandle != nullptr) {
+ if (oldFocusedApplicationHandle != inputApplicationHandle) {
+ if (oldFocusedApplicationHandle != nullptr) {
resetANRTimeoutsLocked();
- mFocusedApplicationHandle->releaseInfo();
+ oldFocusedApplicationHandle->releaseInfo();
}
- mFocusedApplicationHandle = inputApplicationHandle;
+ mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
}
- } else if (mFocusedApplicationHandle != nullptr) {
+ } else if (oldFocusedApplicationHandle != nullptr) {
resetANRTimeoutsLocked();
- mFocusedApplicationHandle->releaseInfo();
- mFocusedApplicationHandle.clear();
+ oldFocusedApplicationHandle->releaseInfo();
+ oldFocusedApplicationHandle.clear();
+ mFocusedApplicationHandlesByDisplay.erase(displayId);
}
#if DEBUG_FOCUS
@@ -3126,6 +3165,62 @@
mLooper->wake();
}
+/**
+ * Sets the focused display, which is responsible for receiving focus-dispatched input events where
+ * the display not specified.
+ *
+ * We track any unreleased events for each window. If a window loses the ability to receive the
+ * released event, we will send a cancel event to it. So when the focused display is changed, we
+ * cancel all the unreleased display-unspecified events for the focused window on the old focused
+ * display. The display-specified events won't be affected.
+ */
+void InputDispatcher::setFocusedDisplay(int32_t displayId) {
+#if DEBUG_FOCUS
+ ALOGD("setFocusedDisplay displayId=%" PRId32, displayId);
+#endif
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ if (mFocusedDisplayId != displayId) {
+ sp<InputWindowHandle> oldFocusedWindowHandle =
+ getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId);
+ if (oldFocusedWindowHandle != nullptr) {
+ sp<InputChannel> inputChannel = oldFocusedWindowHandle->getInputChannel();
+ if (inputChannel != nullptr) {
+ CancelationOptions options(
+ CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS,
+ "The display which contains this window no longer has focus.");
+ synthesizeCancelationEventsForInputChannelLocked(inputChannel, options);
+ }
+ }
+ mFocusedDisplayId = displayId;
+
+ // Sanity check
+ sp<InputWindowHandle> newFocusedWindowHandle =
+ getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+ if (newFocusedWindowHandle == nullptr) {
+ ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
+ if (!mFocusedWindowHandlesByDisplay.empty()) {
+ ALOGE("But another display has a focused window:");
+ for (auto& it : mFocusedWindowHandlesByDisplay) {
+ const int32_t displayId = it.first;
+ const sp<InputWindowHandle>& windowHandle = it.second;
+ ALOGE("Display #%" PRId32 " has focused window: '%s'\n",
+ displayId, windowHandle->getName().c_str());
+ }
+ }
+ }
+ }
+
+#if DEBUG_FOCUS
+ logDispatchStateLocked();
+#endif
+ } // release lock
+
+ // Wake up poll loop since it may need to make new input dispatching choices.
+ mLooper->wake();
+}
+
void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
#if DEBUG_FOCUS
ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen);
@@ -3152,7 +3247,7 @@
}
#if DEBUG_FOCUS
- //logDispatchStateLocked();
+ logDispatchStateLocked();
#endif
} // release lock
@@ -3297,17 +3392,35 @@
void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
dump += StringPrintf(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
dump += StringPrintf(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);
+ dump += StringPrintf(INDENT "FocusedDisplayId: %" PRId32 "\n", mFocusedDisplayId);
- if (mFocusedApplicationHandle != nullptr) {
- dump += StringPrintf(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
- mFocusedApplicationHandle->getName().c_str(),
- mFocusedApplicationHandle->getDispatchingTimeout(
- DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0);
+ if (!mFocusedApplicationHandlesByDisplay.empty()) {
+ dump += StringPrintf(INDENT "FocusedApplications:\n");
+ for (auto& it : mFocusedApplicationHandlesByDisplay) {
+ const int32_t displayId = it.first;
+ const sp<InputApplicationHandle>& applicationHandle = it.second;
+ dump += StringPrintf(
+ INDENT2 "displayId=%" PRId32 ", name='%s', dispatchingTimeout=%0.3fms\n",
+ displayId,
+ applicationHandle->getName().c_str(),
+ applicationHandle->getDispatchingTimeout(
+ DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0);
+ }
} else {
- dump += StringPrintf(INDENT "FocusedApplication: <null>\n");
+ dump += StringPrintf(INDENT "FocusedApplications: <none>\n");
}
- dump += StringPrintf(INDENT "FocusedWindow: name='%s'\n",
- mFocusedWindowHandle != nullptr ? mFocusedWindowHandle->getName().c_str() : "<null>");
+
+ if (!mFocusedWindowHandlesByDisplay.empty()) {
+ dump += StringPrintf(INDENT "FocusedWindows:\n");
+ for (auto& it : mFocusedWindowHandlesByDisplay) {
+ const int32_t displayId = it.first;
+ const sp<InputWindowHandle>& windowHandle = it.second;
+ dump += StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n",
+ displayId, windowHandle->getName().c_str());
+ }
+ } else {
+ dump += StringPrintf(INDENT "FocusedWindows: <none>\n");
+ }
if (!mTouchStatesByDisplay.isEmpty()) {
dump += StringPrintf(INDENT "TouchStatesByDisplay:\n");
@@ -4527,6 +4640,8 @@
return true;
case CancelationOptions::CANCEL_FALLBACK_EVENTS:
return memento.flags & AKEY_EVENT_FLAG_FALLBACK;
+ case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS:
+ return memento.displayId == ADISPLAY_ID_NONE;
default:
return false;
}
@@ -4545,6 +4660,8 @@
return memento.source & AINPUT_SOURCE_CLASS_POINTER;
case CancelationOptions::CANCEL_NON_POINTER_EVENTS:
return !(memento.source & AINPUT_SOURCE_CLASS_POINTER);
+ case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS:
+ return memento.displayId == ADISPLAY_ID_NONE;
default:
return false;
}
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index fdf75f6..aedad2f 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -18,7 +18,9 @@
#define _UI_INPUT_DISPATCHER_H
#include <input/Input.h>
+#include <input/InputApplication.h>
#include <input/InputTransport.h>
+#include <input/InputWindow.h>
#include <utils/KeyedVector.h>
#include <utils/Vector.h>
#include <utils/threads.h>
@@ -33,8 +35,6 @@
#include <limits.h>
#include <unordered_map>
-#include "InputWindow.h"
-#include "InputApplication.h"
#include "InputListener.h"
@@ -311,12 +311,18 @@
virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
int32_t displayId) = 0;
- /* Sets the focused application.
+ /* Sets the focused application on the given display.
*
* This method may be called on any thread (usually by the input manager).
*/
virtual void setFocusedApplication(
- const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
+ int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) = 0;
+
+ /* Sets the focused display.
+ *
+ * This method may be called on any thread (usually by the input manager).
+ */
+ virtual void setFocusedDisplay(int32_t displayId) = 0;
/* Sets the input dispatching mode.
*
@@ -391,7 +397,9 @@
virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
int32_t displayId);
- virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
+ virtual void setFocusedApplication(int32_t displayId,
+ const sp<InputApplicationHandle>& inputApplicationHandle);
+ virtual void setFocusedDisplay(int32_t displayId);
virtual void setInputDispatchMode(bool enabled, bool frozen);
virtual void setInputFilterEnabled(bool enabled);
@@ -686,6 +694,10 @@
CANCEL_POINTER_EVENTS = 1,
CANCEL_NON_POINTER_EVENTS = 2,
CANCEL_FALLBACK_EVENTS = 3,
+
+ /* Cancel events where the display not specified. These events would go to the focused
+ * display. */
+ CANCEL_DISPLAY_UNSPECIFIED_EVENTS = 4,
};
// The criterion to use to determine which events should be canceled.
@@ -966,7 +978,7 @@
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
// Focus tracking for keys, trackball, etc.
- sp<InputWindowHandle> mFocusedWindowHandle;
+ std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay;
// Focus tracking for touch.
struct TouchedWindow {
@@ -997,8 +1009,11 @@
KeyedVector<int32_t, TouchState> mTouchStatesByDisplay;
TouchState mTempTouchState;
- // Focused application.
- sp<InputApplicationHandle> mFocusedApplicationHandle;
+ // Focused applications.
+ std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay;
+
+ // Top focused display.
+ int32_t mFocusedDisplayId;
// Dispatcher state at time of last ANR.
std::string mLastANRState;
@@ -1046,6 +1061,7 @@
nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime);
void resetANRTimeoutsLocked();
+ int32_t getTargetDisplayId(const EventEntry* entry);
int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime);
int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 8f12129..57fc17f 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -258,64 +258,31 @@
bool InputReaderConfiguration::getDisplayViewport(ViewportType viewportType,
const std::string& uniqueDisplayId, DisplayViewport* outViewport) const {
- const DisplayViewport* viewport = nullptr;
- if (viewportType == ViewportType::VIEWPORT_VIRTUAL && !uniqueDisplayId.empty()) {
-
- for (const DisplayViewport& currentViewport : mVirtualDisplays) {
- if (currentViewport.uniqueId == uniqueDisplayId) {
- viewport = ¤tViewport;
- break;
+ for (const DisplayViewport& currentViewport : mDisplays) {
+ if (currentViewport.type == viewportType) {
+ if (uniqueDisplayId.empty() ||
+ (!uniqueDisplayId.empty() && uniqueDisplayId == currentViewport.uniqueId)) {
+ *outViewport = currentViewport;
+ return true;
}
}
- } else if (viewportType == ViewportType::VIEWPORT_EXTERNAL) {
- viewport = &mExternalDisplay;
- } else if (viewportType == ViewportType::VIEWPORT_INTERNAL) {
- viewport = &mInternalDisplay;
- }
-
- if (viewport != nullptr && viewport->displayId >= 0) {
- *outViewport = *viewport;
- return true;
}
return false;
}
-void InputReaderConfiguration::setPhysicalDisplayViewport(ViewportType viewportType,
- const DisplayViewport& viewport) {
- if (viewportType == ViewportType::VIEWPORT_EXTERNAL) {
- mExternalDisplay = viewport;
- } else if (viewportType == ViewportType::VIEWPORT_INTERNAL) {
- mInternalDisplay = viewport;
- }
-}
-
-void InputReaderConfiguration::setVirtualDisplayViewports(
- const Vector<DisplayViewport>& viewports) {
- mVirtualDisplays = viewports;
+void InputReaderConfiguration::setDisplayViewports(const std::vector<DisplayViewport>& viewports) {
+ mDisplays = viewports;
}
void InputReaderConfiguration::dump(std::string& dump) const {
- dump += INDENT4 "ViewportInternal:\n";
- dumpViewport(dump, mInternalDisplay);
- dump += INDENT4 "ViewportExternal:\n";
- dumpViewport(dump, mExternalDisplay);
- dump += INDENT4 "ViewportVirtual:\n";
- for (const DisplayViewport& viewport : mVirtualDisplays) {
+ for (const DisplayViewport& viewport : mDisplays) {
dumpViewport(dump, viewport);
}
}
-void InputReaderConfiguration::dumpViewport(std::string& dump, const DisplayViewport& viewport) const {
- dump += StringPrintf(INDENT5 "Viewport: displayId=%d, orientation=%d, uniqueId='%s', "
- "logicalFrame=[%d, %d, %d, %d], "
- "physicalFrame=[%d, %d, %d, %d], "
- "deviceSize=[%d, %d]\n",
- viewport.displayId, viewport.orientation, viewport.uniqueId.c_str(),
- viewport.logicalLeft, viewport.logicalTop,
- viewport.logicalRight, viewport.logicalBottom,
- viewport.physicalLeft, viewport.physicalTop,
- viewport.physicalRight, viewport.physicalBottom,
- viewport.deviceWidth, viewport.deviceHeight);
+void InputReaderConfiguration::dumpViewport(std::string& dump, const DisplayViewport& viewport)
+ const {
+ dump += StringPrintf(INDENT4 "%s\n", viewport.toString().c_str());
}
@@ -3600,6 +3567,12 @@
break;
}
+ if (naturalPhysicalHeight == 0 || naturalPhysicalWidth == 0) {
+ ALOGE("Viewport is not set properly: %s", mViewport.toString().c_str());
+ naturalPhysicalHeight = naturalPhysicalHeight == 0 ? 1 : naturalPhysicalHeight;
+ naturalPhysicalWidth = naturalPhysicalWidth == 0 ? 1 : naturalPhysicalWidth;
+ }
+
mPhysicalWidth = naturalPhysicalWidth;
mPhysicalHeight = naturalPhysicalHeight;
mPhysicalLeft = naturalPhysicalLeft;
@@ -3913,17 +3886,7 @@
}
void TouchInputMapper::dumpSurface(std::string& dump) {
- dump += StringPrintf(INDENT3 "Viewport: displayId=%d, orientation=%d, "
- "logicalFrame=[%d, %d, %d, %d], "
- "physicalFrame=[%d, %d, %d, %d], "
- "deviceSize=[%d, %d]\n",
- mViewport.displayId, mViewport.orientation,
- mViewport.logicalLeft, mViewport.logicalTop,
- mViewport.logicalRight, mViewport.logicalBottom,
- mViewport.physicalLeft, mViewport.physicalTop,
- mViewport.physicalRight, mViewport.physicalBottom,
- mViewport.deviceWidth, mViewport.deviceHeight);
-
+ dump += StringPrintf(INDENT3 "%s\n", mViewport.toString().c_str());
dump += StringPrintf(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth);
dump += StringPrintf(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index c06168d..74668b7 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -38,6 +38,7 @@
#include <optional>
#include <stddef.h>
#include <unistd.h>
+#include <vector>
// Maximum supported size of a vibration pattern.
// Must be at least 2.
@@ -203,17 +204,14 @@
bool getDisplayViewport(ViewportType viewportType, const std::string& uniqueDisplayId,
DisplayViewport* outViewport) const;
- void setPhysicalDisplayViewport(ViewportType viewportType, const DisplayViewport& viewport);
- void setVirtualDisplayViewports(const Vector<DisplayViewport>& viewports);
+ void setDisplayViewports(const std::vector<DisplayViewport>& viewports);
void dump(std::string& dump) const;
void dumpViewport(std::string& dump, const DisplayViewport& viewport) const;
private:
- DisplayViewport mInternalDisplay;
- DisplayViewport mExternalDisplay;
- Vector<DisplayViewport> mVirtualDisplays;
+ std::vector<DisplayViewport> mDisplays;
};
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
deleted file mode 100644
index 0d1dfdd..0000000
--- a/services/inputflinger/InputWindow.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "InputWindow"
-#define LOG_NDEBUG 0
-
-#include "InputWindow.h"
-
-#include <log/log.h>
-
-#include <ui/Rect.h>
-#include <ui/Region.h>
-
-namespace android {
-
-// --- InputWindowInfo ---
-void InputWindowInfo::addTouchableRegion(const Rect& region) {
- touchableRegion.orSelf(region);
-}
-
-bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
- return touchableRegion.contains(x,y);
-}
-
-bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const {
- return x >= frameLeft && x < frameRight
- && y >= frameTop && y < frameBottom;
-}
-
-bool InputWindowInfo::isTrustedOverlay() const {
- return layoutParamsType == TYPE_INPUT_METHOD
- || layoutParamsType == TYPE_INPUT_METHOD_DIALOG
- || layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
- || layoutParamsType == TYPE_STATUS_BAR
- || layoutParamsType == TYPE_NAVIGATION_BAR
- || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
- || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
- || layoutParamsType == TYPE_DOCK_DIVIDER
- || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY
- || layoutParamsType == TYPE_INPUT_CONSUMER;
-}
-
-bool InputWindowInfo::supportsSplitTouch() const {
- return layoutParamsFlags & FLAG_SPLIT_TOUCH;
-}
-
-bool InputWindowInfo::overlaps(const InputWindowInfo* other) const {
- return frameLeft < other->frameRight && frameRight > other->frameLeft
- && frameTop < other->frameBottom && frameBottom > other->frameTop;
-}
-
-
-// --- InputWindowHandle ---
-
-InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
- inputApplicationHandle(inputApplicationHandle), mInfo(nullptr) {
-}
-
-InputWindowHandle::~InputWindowHandle() {
- delete mInfo;
-}
-
-void InputWindowHandle::releaseInfo() {
- if (mInfo) {
- delete mInfo;
- mInfo = nullptr;
- }
-}
-
-} // namespace android
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 61dcdd9..f75b0b6 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -340,7 +340,8 @@
mDisplayId = displayId;
}
- void consumeEvent(int32_t expectedEventType, int32_t expectedDisplayId) {
+ void consumeEvent(int32_t expectedEventType, int32_t expectedDisplayId,
+ int32_t expectedFlags = 0) {
uint32_t consumeSeq;
InputEvent* event;
status_t status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1,
@@ -351,10 +352,29 @@
ASSERT_TRUE(event != nullptr)
<< mName.c_str() << ": consumer should have returned non-NULL event.";
ASSERT_EQ(expectedEventType, event->getType())
- << mName.c_str() << ": consumer type should same as expected one.";
+ << mName.c_str() << ": event type should match.";
ASSERT_EQ(expectedDisplayId, event->getDisplayId())
- << mName.c_str() << ": consumer displayId should same as expected one.";
+ << mName.c_str() << ": event displayId should be the same as expected.";
+
+ int32_t flags;
+ switch (expectedEventType) {
+ case AINPUT_EVENT_TYPE_KEY: {
+ KeyEvent* typedEvent = static_cast<KeyEvent*>(event);
+ flags = typedEvent->getFlags();
+ break;
+ }
+ case AINPUT_EVENT_TYPE_MOTION: {
+ MotionEvent* typedEvent = static_cast<MotionEvent*>(event);
+ flags = typedEvent->getFlags();
+ break;
+ }
+ default: {
+ FAIL() << mName.c_str() << ": invalid event type: " << expectedEventType;
+ }
+ }
+ ASSERT_EQ(expectedFlags, flags)
+ << mName.c_str() << ": event flags should be the same as expected.";
status = mConsumer->sendFinishedSignal(consumeSeq, true /*handled*/);
ASSERT_EQ(OK, status)
@@ -382,12 +402,13 @@
int32_t mDisplayId;
};
-static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher) {
+static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher,
+ int32_t displayId = ADISPLAY_ID_NONE) {
KeyEvent event;
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
// Define a valid key down event.
- event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
+ event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId,
AKEY_EVENT_ACTION_DOWN, /* flags */ 0,
AKEYCODE_A, KEY_A, AMETA_NONE, /* repeatCount */ 0, currentTime, currentTime);
@@ -466,7 +487,7 @@
sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");
// Set focus application.
- mDispatcher->setFocusedApplication(application);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
// Expect one focus window exist in display.
windowSecond->setFocus();
@@ -511,15 +532,21 @@
windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID);
}
-// TODO(b/111361570): multi-display focus, one focus window per display.
TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
sp<FakeApplicationHandle> application2 = new FakeApplicationHandle();
sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2");
+ constexpr int32_t SECOND_DISPLAY_ID = 1;
+
+ // Set focus to primary display window.
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ windowInPrimary->setFocus();
+
// Set focus to second display window.
- mDispatcher->setFocusedApplication(application2);
+ mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
+ mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2);
windowInSecondary->setFocus();
// Update all windows per displays.
@@ -527,13 +554,18 @@
inputWindowHandles.push(windowInPrimary);
mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
- constexpr int32_t SECOND_DISPLAY_ID = 1;
windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
inputWindowHandles_Second.push(windowInSecondary);
mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
- // Test inject a key down.
+ // Test inject a key down with display id specified.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ windowInPrimary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_DEFAULT);
+ windowInSecondary->assertNoEvents();
+
+ // Test inject a key down without display id specified.
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
<< "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
windowInPrimary->assertNoEvents();
@@ -544,7 +576,8 @@
mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
// Expect old focus should receive a cancel event.
- windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+ windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE,
+ AKEY_EVENT_FLAG_CANCELED);
// Test inject a key down, should timeout because of no target window.
ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 9b985dc..b70ee09 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -132,6 +132,7 @@
InputReaderConfiguration mConfig;
KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers;
Vector<InputDeviceInfo> mInputDevices;
+ std::vector<DisplayViewport> mViewports;
TouchAffineTransformation transform;
protected:
@@ -143,17 +144,20 @@
void setDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
const std::string& uniqueId) {
- DisplayViewport v = createDisplayViewport(displayId, width, height, orientation, uniqueId);
+ mViewports.clear();
// Set the size of both the internal and external display at the same time.
- mConfig.setPhysicalDisplayViewport(ViewportType::VIEWPORT_INTERNAL, v);
- mConfig.setPhysicalDisplayViewport(ViewportType::VIEWPORT_EXTERNAL, v);
+ mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
+ ViewportType::VIEWPORT_INTERNAL));
+ mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
+ ViewportType::VIEWPORT_EXTERNAL));
+ mConfig.setDisplayViewports(mViewports);
}
void setVirtualDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
const std::string& uniqueId) {
- Vector<DisplayViewport> viewports;
- viewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId));
- mConfig.setVirtualDisplayViewports(viewports);
+ mViewports.push_back(createDisplayViewport(displayId, width, height, orientation, uniqueId,
+ ViewportType::VIEWPORT_VIRTUAL));
+ mConfig.setDisplayViewports(mViewports);
}
void addExcludedDeviceName(const std::string& deviceName) {
@@ -203,7 +207,7 @@
private:
DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
- int32_t orientation, const std::string& uniqueId) {
+ int32_t orientation, const std::string& uniqueId, ViewportType type) {
bool isRotated = (orientation == DISPLAY_ORIENTATION_90
|| orientation == DISPLAY_ORIENTATION_270);
DisplayViewport v;
@@ -220,6 +224,7 @@
v.deviceWidth = isRotated ? height : width;
v.deviceHeight = isRotated ? width : height;
v.uniqueId = uniqueId;
+ v.type = type;
return v;
}
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index ebc7eb1..f2336cb 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -16,6 +16,7 @@
#include "SensorDevice.h"
+#include "android/hardware/sensors/2.0/ISensorsCallback.h"
#include "android/hardware/sensors/2.0/types.h"
#include "SensorService.h"
@@ -32,6 +33,7 @@
using namespace android::hardware::sensors;
using namespace android::hardware::sensors::V1_0;
using namespace android::hardware::sensors::V1_0::implementation;
+using android::hardware::sensors::V2_0::ISensorsCallback;
using android::hardware::sensors::V2_0::EventQueueFlagBits;
using android::hardware::hidl_vec;
using android::hardware::Return;
@@ -57,12 +59,53 @@
}
}
+template<typename EnumType>
+constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) {
+ return static_cast<typename std::underlying_type<EnumType>::type>(value);
+}
+
+// Used internally by the framework to wake the Event FMQ. These values must start after
+// the last value of EventQueueFlagBits
+enum EventQueueFlagBitsInternal : uint32_t {
+ INTERNAL_WAKE = 1 << 16,
+};
+
+void SensorsHalDeathReceivier::serviceDied(
+ uint64_t /* cookie */,
+ const wp<::android::hidl::base::V1_0::IBase>& /* service */) {
+ ALOGW("Sensors HAL died, attempting to reconnect.");
+ SensorDevice::getInstance().prepareForReconnect();
+}
+
+struct SensorsCallback : public ISensorsCallback {
+ using Result = ::android::hardware::sensors::V1_0::Result;
+ Return<void> onDynamicSensorsConnected(
+ const hidl_vec<SensorInfo> &dynamicSensorsAdded) override {
+ return SensorDevice::getInstance().onDynamicSensorsConnected(dynamicSensorsAdded);
+ }
+
+ Return<void> onDynamicSensorsDisconnected(
+ const hidl_vec<int32_t> &dynamicSensorHandlesRemoved) override {
+ return SensorDevice::getInstance().onDynamicSensorsDisconnected(
+ dynamicSensorHandlesRemoved);
+ }
+};
+
SensorDevice::SensorDevice()
- : mHidlTransportErrors(20), mRestartWaiter(new HidlServiceRegistrationWaiter()) {
+ : mHidlTransportErrors(20),
+ mRestartWaiter(new HidlServiceRegistrationWaiter()),
+ mReconnecting(false) {
if (!connectHidlService()) {
return;
}
+ initializeSensorList();
+
+ mIsDirectReportSupported =
+ (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
+}
+
+void SensorDevice::initializeSensorList() {
float minPowerMa = 0.001; // 1 microAmp
checkReturn(mSensors->getSensorsList(
@@ -87,9 +130,6 @@
checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
}
}));
-
- mIsDirectReportSupported =
- (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
}
SensorDevice::~SensorDevice() {
@@ -166,19 +206,123 @@
status_t status = StatusFromResult(checkReturn(mSensors->initialize(
*mEventQueue->getDesc(),
*mWakeLockQueue->getDesc(),
- this)));
+ new SensorsCallback())));
if (status != NO_ERROR) {
connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
ALOGE("Failed to initialize Sensors HAL (%s)", strerror(-status));
} else {
connectionStatus = HalConnectionStatus::CONNECTED;
+ mSensorsHalDeathReceiver = new SensorsHalDeathReceivier();
+ sensors->linkToDeath(mSensorsHalDeathReceiver, 0 /* cookie */);
}
}
return connectionStatus;
}
+void SensorDevice::prepareForReconnect() {
+ mReconnecting = true;
+
+ // Wake up the polling thread so it returns and allows the SensorService to initiate
+ // a reconnect.
+ mEventQueueFlag->wake(asBaseType(INTERNAL_WAKE));
+}
+
+void SensorDevice::reconnect() {
+ Mutex::Autolock _l(mLock);
+ mSensors = nullptr;
+
+ auto previousActivations = mActivationCount;
+ auto previousSensorList = mSensorList;
+
+ mActivationCount.clear();
+ mSensorList.clear();
+
+ if (connectHidlServiceV2_0() == HalConnectionStatus::CONNECTED) {
+ initializeSensorList();
+
+ if (sensorHandlesChanged(previousSensorList, mSensorList)) {
+ LOG_ALWAYS_FATAL("Sensor handles changed, cannot re-enable sensors.");
+ } else {
+ reactivateSensors(previousActivations);
+ }
+ }
+ mReconnecting = false;
+}
+
+bool SensorDevice::sensorHandlesChanged(const Vector<sensor_t>& oldSensorList,
+ const Vector<sensor_t>& newSensorList) {
+ bool didChange = false;
+
+ if (oldSensorList.size() != newSensorList.size()) {
+ didChange = true;
+ }
+
+ for (size_t i = 0; i < newSensorList.size() && !didChange; i++) {
+ bool found = false;
+ const sensor_t& newSensor = newSensorList[i];
+ for (size_t j = 0; j < oldSensorList.size() && !found; j++) {
+ const sensor_t& prevSensor = oldSensorList[j];
+ if (prevSensor.handle == newSensor.handle) {
+ found = true;
+ if (!sensorIsEquivalent(prevSensor, newSensor)) {
+ didChange = true;
+ }
+ }
+ }
+
+ if (!found) {
+ // Could not find the new sensor in the old list of sensors, the lists must
+ // have changed.
+ didChange = true;
+ }
+ }
+ return didChange;
+}
+
+bool SensorDevice::sensorIsEquivalent(const sensor_t& prevSensor, const sensor_t& newSensor) {
+ bool equivalent = true;
+ if (prevSensor.handle != newSensor.handle ||
+ (strcmp(prevSensor.vendor, newSensor.vendor) != 0) ||
+ (strcmp(prevSensor.stringType, newSensor.stringType) != 0) ||
+ (strcmp(prevSensor.requiredPermission, newSensor.requiredPermission) != 0) ||
+ (prevSensor.version != newSensor.version) ||
+ (prevSensor.type != newSensor.type) ||
+ (std::abs(prevSensor.maxRange - newSensor.maxRange) > 0.001f) ||
+ (std::abs(prevSensor.resolution - newSensor.resolution) > 0.001f) ||
+ (std::abs(prevSensor.power - newSensor.power) > 0.001f) ||
+ (prevSensor.minDelay != newSensor.minDelay) ||
+ (prevSensor.fifoReservedEventCount != newSensor.fifoReservedEventCount) ||
+ (prevSensor.fifoMaxEventCount != newSensor.fifoMaxEventCount) ||
+ (prevSensor.maxDelay != newSensor.maxDelay) ||
+ (prevSensor.flags != newSensor.flags)) {
+ equivalent = false;
+ }
+ return equivalent;
+}
+
+void SensorDevice::reactivateSensors(const DefaultKeyedVector<int, Info>& previousActivations) {
+ for (size_t i = 0; i < mSensorList.size(); i++) {
+ int handle = mSensorList[i].handle;
+ ssize_t activationIndex = previousActivations.indexOfKey(handle);
+ if (activationIndex < 0 || previousActivations[activationIndex].numActiveClients() <= 0) {
+ continue;
+ }
+
+ const Info& info = previousActivations[activationIndex];
+ for (size_t j = 0; j < info.batchParams.size(); j++) {
+ const BatchParams& batchParams = info.batchParams[j];
+ status_t res = batchLocked(info.batchParams.keyAt(j), handle, 0 /* flags */,
+ batchParams.mTSample, batchParams.mTBatch);
+
+ if (res == NO_ERROR) {
+ activateLocked(info.batchParams.keyAt(j), handle, true /* enabled */);
+ }
+ }
+ }
+}
+
void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) {
// not need to check mSensors because this is is only called after successful poll()
if (connected) {
@@ -236,6 +380,8 @@
}
ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
+ if (mSensors == nullptr) return NO_INIT;
+
ssize_t eventsRead = 0;
if (mSensors->supportsMessageQueues()) {
eventsRead = pollFmq(buffer, count);
@@ -249,8 +395,6 @@
}
ssize_t SensorDevice::pollHal(sensors_event_t* buffer, size_t count) {
- if (mSensors == nullptr) return NO_INIT;
-
ssize_t err;
int numHidlTransportErrors = 0;
bool hidlTransportError = false;
@@ -295,10 +439,6 @@
}
ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead) {
- if (mSensors == nullptr) {
- return NO_INIT;
- }
-
ssize_t eventsRead = 0;
size_t availableEvents = mEventQueue->availableToRead();
@@ -309,13 +449,19 @@
// able to be called with the correct number of events to read. If the specified number of
// events is not available, then read() would return no events, possibly introducing
// additional latency in delivering events to applications.
- mEventQueueFlag->wait(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
- &eventFlagState);
+ mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS) |
+ asBaseType(INTERNAL_WAKE), &eventFlagState);
availableEvents = mEventQueue->availableToRead();
- if (availableEvents == 0) {
+ if ((eventFlagState & asBaseType(EventQueueFlagBits::READ_AND_PROCESS)) &&
+ availableEvents == 0) {
ALOGW("Event FMQ wake without any events");
}
+
+ if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) {
+ ALOGD("Event FMQ internal wake, returning from poll with no events");
+ return DEAD_OBJECT;
+ }
}
size_t eventsToRead = std::min({availableEvents, maxNumEventsToRead, mEventBuffer.size()});
@@ -362,7 +508,8 @@
}
void SensorDevice::writeWakeLockHandled(uint32_t count) {
- if (mSensors->supportsMessageQueues() && !mWakeLockQueue->write(&count)) {
+ if (mSensors != nullptr && mSensors->supportsMessageQueues() &&
+ !mWakeLockQueue->write(&count)) {
ALOGW("Failed to write wake lock handled");
}
}
@@ -381,10 +528,15 @@
status_t SensorDevice::activate(void* ident, int handle, int enabled) {
if (mSensors == nullptr) return NO_INIT;
- status_t err(NO_ERROR);
+ Mutex::Autolock _l(mLock);
+ return activateLocked(ident, handle, enabled);
+}
+
+status_t SensorDevice::activateLocked(void* ident, int handle, int enabled) {
bool actuateHardware = false;
- Mutex::Autolock _l(mLock);
+ status_t err(NO_ERROR);
+
ssize_t activationIndex = mActivationCount.indexOfKey(handle);
if (activationIndex < 0) {
ALOGW("Handle %d cannot be found in activation record", handle);
@@ -484,6 +636,11 @@
ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
Mutex::Autolock _l(mLock);
+ return batchLocked(ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
+}
+
+status_t SensorDevice::batchLocked(void* ident, int handle, int flags, int64_t samplingPeriodNs,
+ int64_t maxBatchReportLatencyNs) {
ssize_t activationIndex = mActivationCount.indexOfKey(handle);
if (activationIndex < 0) {
ALOGW("Handle %d cannot be found in activation record", handle);
@@ -714,7 +871,7 @@
// ---------------------------------------------------------------------------
-int SensorDevice::Info::numActiveClients() {
+int SensorDevice::Info::numActiveClients() const {
SensorDevice& device(SensorDevice::getInstance());
int num = 0;
for (size_t i = 0; i < batchParams.size(); ++i) {
@@ -813,8 +970,12 @@
}
void SensorDevice::handleHidlDeath(const std::string & detail) {
- // restart is the only option at present.
- LOG_ALWAYS_FATAL("Abort due to ISensors hidl service failure, detail: %s.", detail.c_str());
+ if (!SensorDevice::getInstance().mSensors->supportsMessageQueues()) {
+ // restart is the only option at present.
+ LOG_ALWAYS_FATAL("Abort due to ISensors hidl service failure, detail: %s.", detail.c_str());
+ } else {
+ ALOGD("ISensors HAL died, death recipient will attempt reconnect");
+ }
}
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 282550f..e1024ac 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -42,9 +42,12 @@
namespace android {
// ---------------------------------------------------------------------------
+class SensorsHalDeathReceivier : public android::hardware::hidl_death_recipient {
+ virtual void serviceDied(uint64_t cookie,
+ const wp<::android::hidl::base::V1_0::IBase>& service) override;
+};
class SensorDevice : public Singleton<SensorDevice>,
- public android::hardware::sensors::V2_0::ISensorsCallback,
public SensorServiceUtil::Dumpable {
public:
class HidlTransportErrorLog {
@@ -74,6 +77,8 @@
};
~SensorDevice();
+ void prepareForReconnect();
+ void reconnect();
ssize_t getSensorList(sensor_t const** list);
@@ -107,9 +112,13 @@
using Result = ::android::hardware::sensors::V1_0::Result;
hardware::Return<void> onDynamicSensorsConnected(
- const hardware::hidl_vec<hardware::sensors::V1_0::SensorInfo> &dynamicSensorsAdded) override;
+ const hardware::hidl_vec<hardware::sensors::V1_0::SensorInfo> &dynamicSensorsAdded);
hardware::Return<void> onDynamicSensorsDisconnected(
- const hardware::hidl_vec<int32_t> &dynamicSensorHandlesRemoved) override;
+ const hardware::hidl_vec<int32_t> &dynamicSensorHandlesRemoved);
+
+ bool isReconnecting() const {
+ return mReconnecting;
+ }
// Dumpable
virtual std::string dump() const;
@@ -164,7 +173,7 @@
// the removed ident. If index >=0, ident is present and successfully removed.
ssize_t removeBatchParamsForIdent(void* ident);
- int numActiveClients();
+ int numActiveClients() const;
};
DefaultKeyedVector<int, Info> mActivationCount;
@@ -176,6 +185,11 @@
SortedVector<void *> mDisabledClients;
SensorDevice();
bool connectHidlService();
+ void initializeSensorList();
+ void reactivateSensors(const DefaultKeyedVector<int, Info>& previousActivations);
+ static bool sensorHandlesChanged(const Vector<sensor_t>& oldSensorList,
+ const Vector<sensor_t>& newSensorList);
+ static bool sensorIsEquivalent(const sensor_t& prevSensor, const sensor_t& newSensor);
enum HalConnectionStatus {
CONNECTED, // Successfully connected to the HAL
@@ -188,6 +202,9 @@
ssize_t pollHal(sensors_event_t* buffer, size_t count);
ssize_t pollFmq(sensors_event_t* buffer, size_t count);
+ status_t activateLocked(void* ident, int handle, int enabled);
+ status_t batchLocked(void* ident, int handle, int flags, int64_t samplingPeriodNs,
+ int64_t maxBatchReportLatencyNs);
static void handleHidlDeath(const std::string &detail);
template<typename T>
@@ -223,6 +240,9 @@
hardware::EventFlag* mEventQueueFlag;
std::array<Event, SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
+
+ sp<SensorsHalDeathReceivier> mSensorsHalDeathReceiver;
+ std::atomic_bool mReconnecting;
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 7c56e5c..1b9b945 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -47,6 +47,7 @@
#include "SensorRecord.h"
#include "SensorRegistrationInfo.h"
+#include <ctime>
#include <inttypes.h>
#include <math.h>
#include <sched.h>
@@ -423,6 +424,11 @@
} else {
// Default dump the sensor list and debugging information.
//
+ timespec curTime;
+ clock_gettime(CLOCK_REALTIME, &curTime);
+ struct tm* timeinfo = localtime(&(curTime.tv_sec));
+ result.appendFormat("Captured at: %02d:%02d:%02d.%03d\n", timeinfo->tm_hour,
+ timeinfo->tm_min, timeinfo->tm_sec, (int)ns2ms(curTime.tv_nsec));
result.append("Sensor Device:\n");
result.append(SensorDevice::getInstance().dump().c_str());
@@ -627,8 +633,13 @@
do {
ssize_t count = device.poll(mSensorEventBuffer, numEventMax);
if (count < 0) {
- ALOGE("sensor poll failed (%s)", strerror(-count));
- break;
+ if(count == DEAD_OBJECT && device.isReconnecting()) {
+ device.reconnect();
+ continue;
+ } else {
+ ALOGE("sensor poll failed (%s)", strerror(-count));
+ break;
+ }
}
// Reset sensors_event_t.flags to zero for all events in the buffer.
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index dfd0326..6826050 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -98,54 +98,7 @@
mContentsChangedListener = listener;
}
-// We need to determine the time when a buffer acquired now will be
-// displayed. This can be calculated:
-// time when previous buffer's actual-present fence was signaled
-// + current display refresh rate * HWC latency
-// + a little extra padding
-//
-// Buffer producers are expected to set their desired presentation time
-// based on choreographer time stamps, which (coming from vsync events)
-// will be slightly later then the actual-present timing. If we get a
-// desired-present time that is unintentionally a hair after the next
-// vsync, we'll hold the frame when we really want to display it. We
-// need to take the offset between actual-present and reported-vsync
-// into account.
-//
-// If the system is configured without a DispSync phase offset for the app,
-// we also want to throw in a bit of padding to avoid edge cases where we
-// just barely miss. We want to do it here, not in every app. A major
-// source of trouble is the app's use of the display's ideal refresh time
-// (via Display.getRefreshRate()), which could be off of the actual refresh
-// by a few percent, with the error multiplied by the number of frames
-// between now and when the buffer should be displayed.
-//
-// If the refresh reported to the app has a phase offset, we shouldn't need
-// to tweak anything here.
-nsecs_t BufferLayerConsumer::computeExpectedPresent(const DispSync& dispSync) {
- // The HWC doesn't currently have a way to report additional latency.
- // Assume that whatever we submit now will appear right after the flip.
- // For a smart panel this might be 1. This is expressed in frames,
- // rather than time, because we expect to have a constant frame delay
- // regardless of the refresh rate.
- const uint32_t hwcLatency = 0;
-
- // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
- const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);
-
- // The DispSync time is already adjusted for the difference between
- // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
- // we don't need to factor that in here. Pad a little to avoid
- // weird effects if apps might be requesting times right on the edge.
- nsecs_t extraPadding = 0;
- if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
- extraPadding = 1000000; // 1ms (6% of 60Hz)
- }
-
- return nextRefresh + extraPadding;
-}
-
-status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
+status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
bool* autoRefresh, bool* queuedBuffer,
uint64_t maxFrameNumber,
const sp<Fence>& releaseFence) {
@@ -163,7 +116,7 @@
// Acquire the next buffer.
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- status_t err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), maxFrameNumber);
+ status_t err = acquireBufferLocked(&item, expectedPresentTime, maxFrameNumber);
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
err = NO_ERROR;
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index a6610b7..ea46245 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -80,8 +80,6 @@
// ConsumerBase::setFrameAvailableListener().
void setContentsChangedListener(const wp<ContentsChangedListener>& listener);
- nsecs_t computeExpectedPresent(const DispSync& dispSync);
-
// updateTexImage acquires the most recently queued buffer, and sets the
// image contents of the target texture to it.
//
@@ -93,8 +91,8 @@
// Unlike the GLConsumer version, this version takes a functor that may be
// used to reject the newly acquired buffer. It also does not bind the
// RenderEngine texture until bindTextureImage is called.
- status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, bool* autoRefresh,
- bool* queuedBuffer, uint64_t maxFrameNumber,
+ status_t updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
+ bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber,
const sp<Fence>& releaseFence);
// See BufferLayerConsumer::bindTextureImageLocked().
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 576724c..e75fbdf 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -79,7 +79,7 @@
return mQueuedFrames;
}
-bool BufferQueueLayer::shouldPresentNow(const DispSync& dispSync) const {
+bool BufferQueueLayer::shouldPresentNow(nsecs_t expectedPresentTime) const {
if (getSidebandStreamChanged() || getAutoRefresh()) {
return true;
}
@@ -91,7 +91,6 @@
Mutex::Autolock lock(mQueueItemLock);
const int64_t addedTime = mQueueItems[0].mTimestamp;
- const nsecs_t expectedPresentTime = mConsumer->computeExpectedPresent(dispSync);
// Ignore timestamps more than a second in the future
const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1));
@@ -231,8 +230,12 @@
LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
getTransformToDisplayInverse(), mFreezeGeometryUpdates);
+
+ const nsecs_t expectedPresentTime = mFlinger->mUseScheduler
+ ? mFlinger->mScheduler->mPrimaryDispSync->expectedPresentTime()
+ : mFlinger->mPrimaryDispSync->expectedPresentTime();
status_t updateResult =
- mConsumer->updateTexImage(&r, *mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
+ mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh, &queuedBuffer,
mLastFrameNumberReceived, releaseFence);
if (updateResult == BufferQueue::PRESENT_LATER) {
// Producer doesn't want buffer to be displayed yet. Signal a
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 472abf2..abe0bc7 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -55,7 +55,7 @@
int32_t getQueuedFrameCount() const override;
- bool shouldPresentNow(const DispSync& dispSync) const override;
+ bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index c0e85dd..e52b35a 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -56,7 +56,7 @@
return;
}
-bool BufferStateLayer::shouldPresentNow(const DispSync& /*dispSync*/) const {
+bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
if (getSidebandStreamChanged() || getAutoRefresh()) {
return true;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index b106f23..0c6eaf5 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -39,7 +39,7 @@
void setTransformHint(uint32_t orientation) const override;
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
- bool shouldPresentNow(const DispSync& dispSync) const override;
+ bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
bool getTransformToDisplayInverse() const override;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3eb8327..e2d1178 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -395,7 +395,7 @@
virtual void abandon() {}
- virtual bool shouldPresentNow(const DispSync& /*dispSync*/) const { return false; }
+ virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
virtual void setTransformHint(uint32_t /*orientation*/) const { }
/*
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
index 9c2d312..c0174ae 100644
--- a/services/surfaceflinger/LayerStats.cpp
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -68,7 +68,7 @@
base::StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
base::StringAppendF(&key, ",%d", layer->isProtected);
base::StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform));
- base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format));
+ base::StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format).c_str());
base::StringAppendF(&key, ",%s", layer->dataspace.c_str());
base::StringAppendF(&key, ",%s",
destinationLocation(layer->hwcFrame.left, layerGlobal.resolution[0],
@@ -162,8 +162,8 @@
return getCompositionName(static_cast<hwc2_composition_t>(compositionType));
}
-const char* LayerStats::layerPixelFormat(int32_t pixelFormat) {
- return decodePixelFormat(pixelFormat).c_str();
+std::string LayerStats::layerPixelFormat(int32_t pixelFormat) {
+ return decodePixelFormat(pixelFormat);
}
std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
index 944073b..9de9cce 100644
--- a/services/surfaceflinger/LayerStats.h
+++ b/services/surfaceflinger/LayerStats.h
@@ -50,7 +50,7 @@
// Return the name of the composition type
static const char* layerCompositionType(int32_t compositionType);
// Return the name of the pixel format
- static const char* layerPixelFormat(int32_t pixelFormat);
+ static std::string layerPixelFormat(int32_t pixelFormat);
// Calculate scale ratios of layer's width/height with rotation information
static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
// Calculate scale ratio from source to destination and convert to string
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp
index 5a3c2c8..809a0d7 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/services/surfaceflinger/RenderEngine/Mesh.cpp
@@ -27,7 +27,7 @@
mTexCoordsSize(texCoordSize),
mPrimitive(primitive) {
if (vertexCount == 0) {
- mVertices = new float[1];
+ mVertices.resize(1);
mVertices[0] = 0.0f;
mStride = 0;
return;
@@ -40,7 +40,7 @@
// will be equal to stride as long as stride * vertexCount doesn't overflow.
if ((stride < vertexSize) || (remainder != stride)) {
ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize, texCoordSize);
- mVertices = new float[1];
+ mVertices.resize(1);
mVertices[0] = 0.0f;
mVertexCount = 0;
mVertexSize = 0;
@@ -49,30 +49,26 @@
return;
}
- mVertices = new float[stride * vertexCount];
+ mVertices.resize(stride * vertexCount);
mStride = stride;
}
-Mesh::~Mesh() {
- delete[] mVertices;
-}
-
Mesh::Primitive Mesh::getPrimitive() const {
return mPrimitive;
}
float const* Mesh::getPositions() const {
- return mVertices;
+ return mVertices.data();
}
float* Mesh::getPositions() {
- return mVertices;
+ return mVertices.data();
}
float const* Mesh::getTexCoords() const {
- return mVertices + mVertexSize;
+ return mVertices.data() + mVertexSize;
}
float* Mesh::getTexCoords() {
- return mVertices + mVertexSize;
+ return mVertices.data() + mVertexSize;
}
size_t Mesh::getVertexCount() const {
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
index 1b0a539..5c4c3d5 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
@@ -35,6 +35,7 @@
#include <ui/DebugUtils.h>
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/Trace.h>
#include "GLExtensions.h"
@@ -115,28 +116,27 @@
EGLint wanted, EGLConfig* outConfig) {
EGLint numConfigs = -1, n = 0;
eglGetConfigs(dpy, nullptr, 0, &numConfigs);
- EGLConfig* const configs = new EGLConfig[numConfigs];
- eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
+ std::vector<EGLConfig> configs(numConfigs, EGL_NO_CONFIG_KHR);
+ eglChooseConfig(dpy, attrs, configs.data(), configs.size(), &n);
+ configs.resize(n);
- if (n) {
+ if (!configs.empty()) {
if (attribute != EGL_NONE) {
- for (int i = 0; i < n; i++) {
+ for (EGLConfig config : configs) {
EGLint value = 0;
- eglGetConfigAttrib(dpy, configs[i], attribute, &value);
+ eglGetConfigAttrib(dpy, config, attribute, &value);
if (wanted == value) {
- *outConfig = configs[i];
- delete[] configs;
+ *outConfig = config;
return NO_ERROR;
}
}
} else {
// just pick the first one
*outConfig = configs[0];
- delete[] configs;
return NO_ERROR;
}
}
- delete[] configs;
+
return NAME_NOT_FOUND;
}
@@ -883,6 +883,10 @@
result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
extensions.getVersion());
result.appendFormat("%s\n", extensions.getExtensions());
+
+ result.appendFormat("RenderEngine program cache size: %zu\n",
+ ProgramCache::getInstance().getSize());
+
result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
diff --git a/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
index 6f50ea7..0fdb9aa 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLExtensions.cpp
@@ -16,6 +16,9 @@
#include "GLExtensions.h"
+#include <string>
+#include <unordered_set>
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -26,22 +29,30 @@
namespace renderengine {
namespace gl {
-SortedVector<String8> GLExtensions::parseExtensionString(char const* extensions) {
- SortedVector<String8> list;
+namespace {
- char const* curr = extensions;
- char const* head = curr;
- do {
- head = strchr(curr, ' ');
- String8 s(curr, head ? head - curr : strlen(curr));
- if (s.length()) {
- list.add(s);
- }
- curr = head + 1;
- } while (head);
+class ExtensionSet {
+public:
+ ExtensionSet(const char* extensions) {
+ char const* curr = extensions;
+ char const* head = curr;
+ do {
+ head = strchr(curr, ' ');
+ size_t len = head ? head - curr : strlen(curr);
+ if (len > 0) {
+ mExtensions.emplace(curr, len);
+ }
+ curr = head + 1;
+ } while (head);
+ }
- return list;
-}
+ bool hasExtension(const char* extension) const { return mExtensions.count(extension) > 0; }
+
+private:
+ std::unordered_set<std::string> mExtensions;
+};
+
+} // anonymous namespace
void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer,
GLubyte const* version, GLubyte const* extensions) {
@@ -49,12 +60,6 @@
mRenderer = (char const*)renderer;
mVersion = (char const*)version;
mExtensions = (char const*)extensions;
- mExtensionList = parseExtensionString(mExtensions);
-}
-
-bool GLExtensions::hasExtension(char const* extension) const {
- const String8 s(extension);
- return mExtensionList.indexOf(s) >= 0;
}
char const* GLExtensions::getVendor() const {
@@ -76,7 +81,8 @@
void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExtensions) {
mEGLVersion = eglVersion;
mEGLExtensions = eglExtensions;
- mEGLExtensionList = parseExtensionString(mEGLExtensions);
+
+ ExtensionSet extensionSet(eglExtensions);
// EGL_ANDROIDX_no_config_context is an experimental extension with no
// written specification. It will be replaced by something more formal.
@@ -86,24 +92,24 @@
//
// EGL_KHR_no_config_context is official extension to allow creating a
// context that works with any surface of a display.
- if (hasEGLExtension("EGL_ANDROIDX_no_config_context") ||
- hasEGLExtension("EGL_KHR_no_config_context")) {
+ if (extensionSet.hasExtension("EGL_ANDROIDX_no_config_context") ||
+ extensionSet.hasExtension("EGL_KHR_no_config_context")) {
mHasNoConfigContext = true;
}
- if (hasEGLExtension("EGL_ANDROID_native_fence_sync")) {
+ if (extensionSet.hasExtension("EGL_ANDROID_native_fence_sync")) {
mHasNativeFenceSync = true;
}
- if (hasEGLExtension("EGL_KHR_fence_sync")) {
+ if (extensionSet.hasExtension("EGL_KHR_fence_sync")) {
mHasFenceSync = true;
}
- if (hasEGLExtension("EGL_KHR_wait_sync")) {
+ if (extensionSet.hasExtension("EGL_KHR_wait_sync")) {
mHasWaitSync = true;
}
- if (hasEGLExtension("EGL_EXT_protected_content")) {
+ if (extensionSet.hasExtension("EGL_EXT_protected_content")) {
mHasProtectedContent = true;
}
- if (hasEGLExtension("EGL_IMG_context_priority")) {
+ if (extensionSet.hasExtension("EGL_IMG_context_priority")) {
mHasContextPriority = true;
}
}
@@ -116,11 +122,6 @@
return mEGLExtensions.string();
}
-bool GLExtensions::hasEGLExtension(char const* extension) const {
- const String8 s(extension);
- return mEGLExtensionList.indexOf(s) >= 0;
-}
-
} // namespace gl
} // namespace renderengine
} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLExtensions.h b/services/surfaceflinger/RenderEngine/gl/GLExtensions.h
index efdd8b7..02ad965 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/gl/GLExtensions.h
@@ -25,7 +25,6 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <utils/Singleton.h>
-#include <utils/SortedVector.h>
#include <utils/String8.h>
namespace android {
@@ -46,13 +45,9 @@
String8 mRenderer;
String8 mVersion;
String8 mExtensions;
- SortedVector<String8> mExtensionList;
String8 mEGLVersion;
String8 mEGLExtensions;
- SortedVector<String8> mEGLExtensionList;
-
- static SortedVector<String8> parseExtensionString(char const* extensions);
GLExtensions(const GLExtensions&);
GLExtensions& operator=(const GLExtensions&);
@@ -74,12 +69,10 @@
char const* getRenderer() const;
char const* getVersion() const;
char const* getExtensions() const;
- bool hasExtension(char const* extension) const;
void initWithEGLStrings(char const* eglVersion, char const* eglExtensions);
char const* getEGLVersion() const;
char const* getEGLExtensions() const;
- bool hasEGLExtension(char const* extension) const;
};
} // namespace gl
diff --git a/services/surfaceflinger/RenderEngine/gl/Program.cpp b/services/surfaceflinger/RenderEngine/gl/Program.cpp
index da67f92..7ae5736 100644
--- a/services/surfaceflinger/RenderEngine/gl/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/Program.cpp
@@ -74,8 +74,6 @@
}
}
-Program::~Program() {}
-
bool Program::isValid() const {
return mInitialized;
}
@@ -112,17 +110,6 @@
return shader;
}
-String8& Program::dumpShader(String8& result, GLenum /*type*/) {
- GLuint shader = GL_FRAGMENT_SHADER ? mFragmentShader : mVertexShader;
- GLint l;
- glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &l);
- char* src = new char[l];
- glGetShaderSource(shader, l, nullptr, src);
- result.append(src);
- delete[] src;
- return result;
-}
-
void Program::setUniforms(const Description& desc) {
// TODO: we should have a mechanism here to not always reset uniforms that
// didn't change for this program.
diff --git a/services/surfaceflinger/RenderEngine/gl/Program.h b/services/surfaceflinger/RenderEngine/gl/Program.h
index bb429ef..b1ce8cf 100644
--- a/services/surfaceflinger/RenderEngine/gl/Program.h
+++ b/services/surfaceflinger/RenderEngine/gl/Program.h
@@ -39,7 +39,7 @@
enum { position = 0, texCoords = 1 };
Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment);
- ~Program();
+ ~Program() = default;
/* whether this object is usable */
bool isValid() const;
@@ -58,7 +58,6 @@
private:
GLuint buildShader(const char* source, GLenum type);
- String8& dumpShader(String8& result, GLenum type);
// whether the initialization succeeded
bool mInitialized;
diff --git a/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
index 9254aa0..6d431b6 100644
--- a/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/ProgramCache.cpp
@@ -20,6 +20,7 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include <log/log.h>
#include <renderengine/private/Description.h>
#include <utils/String8.h>
#include <utils/Trace.h>
@@ -76,10 +77,6 @@
return f;
}
-ProgramCache::ProgramCache() {}
-
-ProgramCache::~ProgramCache() {}
-
void ProgramCache::primeCache(bool useColorManagement) {
uint32_t shaderCount = 0;
uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK;
@@ -94,10 +91,8 @@
if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) {
continue;
}
- Program* program = mCache.valueFor(shaderKey);
- if (program == nullptr) {
- program = generateProgram(shaderKey);
- mCache.add(shaderKey, program);
+ if (mCache.count(shaderKey) == 0) {
+ mCache.emplace(shaderKey, generateProgram(shaderKey));
shaderCount++;
}
}
@@ -113,10 +108,8 @@
shaderKey.set(Key::OPACITY_MASK,
(i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT);
shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE);
- Program* program = mCache.valueFor(shaderKey);
- if (program == nullptr) {
- program = generateProgram(shaderKey);
- mCache.add(shaderKey, program);
+ if (mCache.count(shaderKey) == 0) {
+ mCache.emplace(shaderKey, generateProgram(shaderKey));
shaderCount++;
}
}
@@ -316,7 +309,7 @@
// scale [0.0, maxInLumi] to [0.0, maxOutLumi]
if (maxInLumi <= maxOutLumi) {
- nits *= maxOutLumi / maxInLumi;
+ return color * (maxOutLumi / maxInLumi);
} else {
// three control points
const float x0 = 10.0;
@@ -337,7 +330,7 @@
if (nits < x0) {
// scale [0.0, x0] to [0.0, y0] linearly
float slope = y0 / x0;
- nits *= slope;
+ return color * slope;
} else if (nits < x1) {
// scale [x0, x1] to [y0, y1] linearly
float slope = (y1 - y0) / (x1 - x0);
@@ -355,7 +348,8 @@
}
}
- return color * (nits / max(1e-6, color.y));
+ // color.y is greater than x0 and is thus non-zero
+ return color * (nits / color.y);
}
)__SHADER__";
break;
@@ -386,7 +380,7 @@
if (nits <= x0) {
// scale [0.0, x0] to [0.0, y0] linearly
const float slope = y0 / x0;
- nits *= slope;
+ return color * slope;
} else if (nits <= x1) {
// scale [x0, x1] to [y0, y1] using a curve
float t = (nits - x0) / (x1 - x0);
@@ -401,7 +395,8 @@
nits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 + t * t * y3;
}
- return color * (nits / max(1e-6, color.y));
+ // color.y is greater than x0 and is thus non-zero
+ return color * (nits / color.y);
}
)__SHADER__";
break;
@@ -574,7 +569,7 @@
fs << "uniform mat4 inputTransformMatrix;";
fs << R"__SHADER__(
highp vec3 InputTransform(const highp vec3 color) {
- return vec3(inputTransformMatrix * vec4(color, 1.0));
+ return clamp(vec3(inputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0);
}
)__SHADER__";
} else {
@@ -647,7 +642,7 @@
return fs.getString();
}
-Program* ProgramCache::generateProgram(const Key& needs) {
+std::unique_ptr<Program> ProgramCache::generateProgram(const Key& needs) {
ATRACE_CALL();
// vertex shader
@@ -656,8 +651,7 @@
// fragment shader
String8 fs = generateFragmentShader(needs);
- Program* program = new Program(needs, vs.string(), fs.string());
- return program;
+ return std::make_unique<Program>(needs, vs.string(), fs.string());
}
void ProgramCache::useProgram(const Description& description) {
@@ -665,19 +659,19 @@
Key needs(computeKey(description));
// look-up the program in the cache
- Program* program = mCache.valueFor(needs);
- if (program == nullptr) {
+ auto it = mCache.find(needs);
+ if (it == mCache.end()) {
// we didn't find our program, so generate one...
- nsecs_t time = -systemTime();
- program = generateProgram(needs);
- mCache.add(needs, program);
- time += systemTime();
+ nsecs_t time = systemTime();
+ it = mCache.emplace(needs, generateProgram(needs)).first;
+ time = systemTime() - time;
ALOGV(">>> generated new program: needs=%08X, time=%u ms (%zu programs)", needs.mKey,
uint32_t(ns2ms(time)), mCache.size());
}
// here we have a suitable program for this description
+ std::unique_ptr<Program>& program = it->second;
if (program->isValid()) {
program->use();
program->setUniforms(description);
diff --git a/services/surfaceflinger/RenderEngine/gl/ProgramCache.h b/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
index 47963eb..120b3d1 100644
--- a/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/gl/ProgramCache.h
@@ -17,9 +17,11 @@
#ifndef SF_RENDER_ENGINE_PROGRAMCACHE_H
#define SF_RENDER_ENGINE_PROGRAMCACHE_H
+#include <memory>
+#include <unordered_map>
+
#include <GLES2/gl2.h>
#include <renderengine/private/Description.h>
-#include <utils/KeyedVector.h>
#include <utils/Singleton.h>
#include <utils/TypeHelpers.h>
@@ -155,18 +157,27 @@
}
inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; }
- // this is the definition of a friend function -- not a method of class Needs
- friend inline int strictly_order_type(const Key& lhs, const Key& rhs) {
- return (lhs.mKey < rhs.mKey) ? 1 : 0;
+ // for use by std::unordered_map
+
+ bool operator==(const Key& other) const {
+ return mKey == other.mKey;
}
+
+ struct Hash {
+ size_t operator()(const Key& key) const {
+ return static_cast<size_t>(key.mKey);
+ }
+ };
};
- ProgramCache();
- ~ProgramCache();
+ ProgramCache() = default;
+ ~ProgramCache() = default;
// Generate shaders to populate the cache
void primeCache(bool useColorManagement);
+ size_t getSize() const { return mCache.size(); }
+
// useProgram lookup a suitable program in the cache or generates one
// if none can be found.
void useProgram(const Description& description);
@@ -183,15 +194,15 @@
// Generate OETF based from Key.
static void generateOETF(Formatter& fs, const Key& needs);
// generates a program from the Key
- static Program* generateProgram(const Key& needs);
+ static std::unique_ptr<Program> generateProgram(const Key& needs);
// generates the vertex shader from the Key
static String8 generateVertexShader(const Key& needs);
// generates the fragment shader from the Key
static String8 generateFragmentShader(const Key& needs);
// Key/Value map used for caching Programs. Currently the cache
- // is never shrunk.
- DefaultKeyedVector<Key, Program*> mCache;
+ // is never shrunk (and the GL program objects are never deleted).
+ std::unordered_map<Key, std::unique_ptr<Program>, Key::Hash> mCache;
};
} // namespace gl
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h b/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
index 39ca2f7..15d2a11 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/Mesh.h
@@ -17,6 +17,8 @@
#ifndef SF_RENDER_ENGINE_MESH_H
#define SF_RENDER_ENGINE_MESH_H
+#include <vector>
+
#include <stdint.h>
namespace android {
@@ -31,7 +33,7 @@
};
Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordsSize = 0);
- ~Mesh();
+ ~Mesh() = default;
/*
* VertexArray handles the stride automatically.
@@ -90,7 +92,8 @@
float* getPositions();
float* getTexCoords();
- float* mVertices;
+
+ std::vector<float> mVertices;
size_t mVertexCount;
size_t mVertexSize;
size_t mTexCoordsSize;
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 54a1b51..cba9181 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -44,10 +44,6 @@
namespace impl {
-// Setting this to true enables verbose tracing that can be used to debug
-// vsync event model or phase issues.
-static const bool kTraceDetailedInfo = false;
-
// Setting this to true adds a zero-phase tracer for correlating with hardware
// vsync events
static const bool kEnableZeroPhaseTracer = false;
@@ -62,19 +58,20 @@
#define LOG_TAG "DispSyncThread"
class DispSyncThread : public Thread {
public:
- explicit DispSyncThread(const char* name)
+ DispSyncThread(const char* name, bool showTraceDetailedInfo)
: mName(name),
mStop(false),
mPeriod(0),
mPhase(0),
mReferenceTime(0),
mWakeupLatency(0),
- mFrameNumber(0) {}
+ mFrameNumber(0),
+ mTraceDetailedInfo(showTraceDetailedInfo) {}
virtual ~DispSyncThread() {}
void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
- if (kTraceDetailedInfo) ATRACE_CALL();
+ if (mTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
mPeriod = period;
mPhase = phase;
@@ -86,7 +83,7 @@
}
void stop() {
- if (kTraceDetailedInfo) ATRACE_CALL();
+ if (mTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
mStop = true;
mCond.signal();
@@ -104,7 +101,7 @@
{ // Scope for lock
Mutex::Autolock lock(mMutex);
- if (kTraceDetailedInfo) {
+ if (mTraceDetailedInfo) {
ATRACE_INT64("DispSync:Frame", mFrameNumber);
}
ALOGV("[%s] Frame %" PRId64, mName, mFrameNumber);
@@ -128,7 +125,7 @@
bool isWakeup = false;
if (now < targetTime) {
- if (kTraceDetailedInfo) ATRACE_NAME("DispSync waiting");
+ if (mTraceDetailedInfo) ATRACE_NAME("DispSync waiting");
if (targetTime == INT64_MAX) {
ALOGV("[%s] Waiting forever", mName);
@@ -154,7 +151,7 @@
if (isWakeup) {
mWakeupLatency = ((mWakeupLatency * 63) + (now - targetTime)) / 64;
mWakeupLatency = min(mWakeupLatency, kMaxWakeupLatency);
- if (kTraceDetailedInfo) {
+ if (mTraceDetailedInfo) {
ATRACE_INT64("DispSync:WakeupLat", now - targetTime);
ATRACE_INT64("DispSync:AvgWakeupLat", mWakeupLatency);
}
@@ -172,7 +169,7 @@
}
status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback) {
- if (kTraceDetailedInfo) ATRACE_CALL();
+ if (mTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
for (size_t i = 0; i < mEventListeners.size(); i++) {
@@ -198,7 +195,7 @@
}
status_t removeEventListener(DispSync::Callback* callback) {
- if (kTraceDetailedInfo) ATRACE_CALL();
+ if (mTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
for (std::vector<EventListener>::iterator it = mEventListeners.begin();
@@ -214,7 +211,7 @@
}
status_t changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) {
- if (kTraceDetailedInfo) ATRACE_CALL();
+ if (mTraceDetailedInfo) ATRACE_CALL();
Mutex::Autolock lock(mMutex);
for (auto& eventListener : mEventListeners) {
@@ -254,7 +251,7 @@
};
nsecs_t computeNextEventTimeLocked(nsecs_t now) {
- if (kTraceDetailedInfo) ATRACE_CALL();
+ if (mTraceDetailedInfo) ATRACE_CALL();
ALOGV("[%s] computeNextEventTimeLocked", mName);
nsecs_t nextEventTime = INT64_MAX;
for (size_t i = 0; i < mEventListeners.size(); i++) {
@@ -270,7 +267,7 @@
}
std::vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
- if (kTraceDetailedInfo) ATRACE_CALL();
+ if (mTraceDetailedInfo) ATRACE_CALL();
ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now));
std::vector<CallbackInvocation> callbackInvocations;
@@ -293,7 +290,7 @@
}
nsecs_t computeListenerNextEventTimeLocked(const EventListener& listener, nsecs_t baseTime) {
- if (kTraceDetailedInfo) ATRACE_CALL();
+ if (mTraceDetailedInfo) ATRACE_CALL();
ALOGV("[%s] [%s] computeListenerNextEventTimeLocked(%" PRId64 ")", mName, listener.mName,
ns2us(baseTime));
@@ -344,7 +341,7 @@
}
void fireCallbackInvocations(const std::vector<CallbackInvocation>& callbacks) {
- if (kTraceDetailedInfo) ATRACE_CALL();
+ if (mTraceDetailedInfo) ATRACE_CALL();
for (size_t i = 0; i < callbacks.size(); i++) {
callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
}
@@ -365,6 +362,9 @@
Mutex mMutex;
Condition mCond;
+
+ // Flag to turn on logging in systrace.
+ const bool mTraceDetailedInfo;
};
#undef LOG_TAG
@@ -383,8 +383,13 @@
bool mParity;
};
-DispSync::DispSync(const char* name)
- : mName(name), mRefreshSkipCount(0), mThread(new DispSyncThread(name)) {}
+DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0) {
+ // This flag offers the ability to turn on systrace logging from the shell.
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.sf.dispsync_trace_detailed_info", value, "0");
+ mTraceDetailedInfo = atoi(value);
+ mThread = new DispSyncThread(name, mTraceDetailedInfo);
+}
DispSync::~DispSync() {}
@@ -403,7 +408,7 @@
reset();
beginResync();
- if (kTraceDetailedInfo && kEnableZeroPhaseTracer) {
+ if (mTraceDetailedInfo && kEnableZeroPhaseTracer) {
mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get());
}
@@ -588,7 +593,7 @@
ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase));
}
- if (kTraceDetailedInfo) {
+ if (mTraceDetailedInfo) {
ATRACE_INT64("DispSync:Period", mPeriod);
ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
}
@@ -647,7 +652,7 @@
"No present times for model error.");
}
- if (kTraceDetailedInfo) {
+ if (mTraceDetailedInfo) {
ATRACE_INT64("DispSync:Error", mError);
}
}
@@ -726,6 +731,54 @@
result.appendFormat("current monotonic time: %" PRId64 "\n", now);
}
+// TODO(b/113612090): Figure out how much of this is still relevant.
+// We need to determine the time when a buffer acquired now will be
+// displayed. This can be calculated:
+// time when previous buffer's actual-present fence was signaled
+// + current display refresh rate * HWC latency
+// + a little extra padding
+//
+// Buffer producers are expected to set their desired presentation time
+// based on choreographer time stamps, which (coming from vsync events)
+// will be slightly later then the actual-present timing. If we get a
+// desired-present time that is unintentionally a hair after the next
+// vsync, we'll hold the frame when we really want to display it. We
+// need to take the offset between actual-present and reported-vsync
+// into account.
+//
+// If the system is configured without a DispSync phase offset for the app,
+// we also want to throw in a bit of padding to avoid edge cases where we
+// just barely miss. We want to do it here, not in every app. A major
+// source of trouble is the app's use of the display's ideal refresh time
+// (via Display.getRefreshRate()), which could be off of the actual refresh
+// by a few percent, with the error multiplied by the number of frames
+// between now and when the buffer should be displayed.
+//
+// If the refresh reported to the app has a phase offset, we shouldn't need
+// to tweak anything here.
+nsecs_t DispSync::expectedPresentTime() {
+ // The HWC doesn't currently have a way to report additional latency.
+ // Assume that whatever we submit now will appear right after the flip.
+ // For a smart panel this might be 1. This is expressed in frames,
+ // rather than time, because we expect to have a constant frame delay
+ // regardless of the refresh rate.
+ const uint32_t hwcLatency = 0;
+
+ // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
+ const nsecs_t nextRefresh = computeNextRefresh(hwcLatency);
+
+ // The DispSync time is already adjusted for the difference between
+ // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
+ // we don't need to factor that in here. Pad a little to avoid
+ // weird effects if apps might be requesting times right on the edge.
+ nsecs_t extraPadding = 0;
+ if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
+ extraPadding = 1000000; // 1ms (6% of 60Hz)
+ }
+
+ return nextRefresh + extraPadding;
+}
+
} // namespace impl
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index b3aef2d..5b511f4 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -57,6 +57,7 @@
virtual status_t changePhaseOffset(Callback* callback, nsecs_t phase) = 0;
virtual nsecs_t computeNextRefresh(int periodOffset) const = 0;
virtual void setIgnorePresentFences(bool ignore) = 0;
+ virtual nsecs_t expectedPresentTime() = 0;
virtual void dump(String8& result) const = 0;
};
@@ -164,6 +165,9 @@
// true from addPresentFence() and addResyncSample().
void setIgnorePresentFences(bool ignore) override;
+ // Determine the expected present time when a buffer acquired now will be displayed.
+ nsecs_t expectedPresentTime();
+
// dump appends human-readable debug info to the result string.
void dump(String8& result) const override;
@@ -237,6 +241,9 @@
bool mIgnorePresentFences;
std::unique_ptr<Callback> mZeroPhaseTracer;
+
+ // Flag to turn on logging in systrace.
+ bool mTraceDetailedInfo = false;
};
} // namespace impl
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 54e19c7..18a8bb1 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -20,15 +20,25 @@
#include <cstdint>
#include <memory>
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
#include <gui/ISurfaceComposer.h>
+#include <ui/DisplayStatInfo.h>
#include "DispSync.h"
#include "DispSyncSource.h"
+#include "EventControlThread.h"
#include "EventThread.h"
#include "InjectVSyncSource.h"
namespace android {
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
#define RETURN_VALUE_IF_INVALID(value) \
if (handle == nullptr || mConnections.count(handle->id) == 0) return value
#define RETURN_IF_INVALID() \
@@ -36,17 +46,34 @@
std::atomic<int64_t> Scheduler::sNextId = 0;
+Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function)
+ : mHasSyncFramework(
+ getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasSyncFramework>(true)),
+ mDispSyncPresentTimeOffset(
+ getInt64<ISurfaceFlingerConfigs,
+ &ISurfaceFlingerConfigs::presentTimeOffsetFromVSyncNs>(0)),
+ mPrimaryHWVsyncEnabled(false),
+ mHWVsyncAvailable(false) {
+ // Note: We create a local temporary with the real DispSync implementation
+ // type temporarily so we can initialize it with the configured values,
+ // before storing it for more generic use using the interface type.
+ auto primaryDispSync = std::make_unique<impl::DispSync>("SchedulerDispSync");
+ primaryDispSync->init(mHasSyncFramework, mDispSyncPresentTimeOffset);
+ mPrimaryDispSync = std::move(primaryDispSync);
+ mEventControlThread = std::make_unique<impl::EventControlThread>(function);
+}
+
Scheduler::~Scheduler() = default;
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
- const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ const std::string& connectionName, int64_t phaseOffsetNs,
impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
std::unique_ptr<EventThread> eventThread =
- makeEventThread(connectionName, dispSync, phaseOffsetNs, resyncCallback,
+ makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs, resyncCallback,
interceptCallback);
auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
eventThread->createEventConnection(),
@@ -108,4 +135,65 @@
RETURN_IF_INVALID();
mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
}
+
+void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
+ stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+ stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
+}
+
+void Scheduler::enableHardwareVsync() {
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
+ if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
+ mPrimaryDispSync->beginResync();
+ mEventControlThread->setVsyncEnabled(true);
+ mPrimaryHWVsyncEnabled = true;
+ }
+}
+
+void Scheduler::disableHardwareVsync(bool makeUnavailable) {
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
+ if (mPrimaryHWVsyncEnabled) {
+ mEventControlThread->setVsyncEnabled(false);
+ mPrimaryDispSync->endResync();
+ mPrimaryHWVsyncEnabled = false;
+ }
+ if (makeUnavailable) {
+ mHWVsyncAvailable = false;
+ }
+}
+
+void Scheduler::setVsyncPeriod(const nsecs_t period) {
+ mPrimaryDispSync->reset();
+ mPrimaryDispSync->setPeriod(period);
+ enableHardwareVsync();
+}
+
+void Scheduler::addResyncSample(const nsecs_t timestamp) {
+ bool needsHwVsync = false;
+ { // Scope for the lock
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
+ if (mPrimaryHWVsyncEnabled) {
+ needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
+ }
+ }
+
+ if (needsHwVsync) {
+ enableHardwareVsync();
+ } else {
+ disableHardwareVsync(false);
+ }
+}
+
+void Scheduler::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
+ if (mPrimaryDispSync->addPresentFence(fenceTime)) {
+ enableHardwareVsync();
+ } else {
+ disableHardwareVsync(false);
+ }
+}
+
+void Scheduler::setIgnorePresentFences(bool ignore) {
+ mPrimaryDispSync->setIgnorePresentFences(ignore);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index fcb46e6..fdafe58 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -20,22 +20,31 @@
#include <memory>
#include <gui/ISurfaceComposer.h>
+#include <ui/DisplayStatInfo.h>
#include "DispSync.h"
+#include "EventControlThread.h"
#include "EventThread.h"
#include "InjectVSyncSource.h"
namespace android {
+class EventControlThread;
+
class Scheduler {
public:
+ // Enum to indicate whether to start the transaction early, or at vsync time.
+ enum class TransactionStart { EARLY, NORMAL };
+
/* The scheduler handle is a BBinder object passed to the client from which we can extract
* an ID for subsequent operations.
*/
class ConnectionHandle : public BBinder {
public:
ConnectionHandle(int64_t id) : id(id) {}
+
~ConnectionHandle() = default;
+
const int64_t id;
};
@@ -44,6 +53,7 @@
Connection(sp<ConnectionHandle> handle, sp<BnDisplayEventConnection> eventConnection,
std::unique_ptr<EventThread> eventThread)
: handle(handle), eventConnection(eventConnection), thread(std::move(eventThread)) {}
+
~Connection() = default;
sp<ConnectionHandle> handle;
@@ -51,32 +61,48 @@
const std::unique_ptr<EventThread> thread;
};
- Scheduler() = default;
+ explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function);
+
virtual ~Scheduler();
/** Creates an EventThread connection. */
sp<ConnectionHandle> createConnection(
- const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ const std::string& connectionName, int64_t phaseOffsetNs,
impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback);
+
sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle);
// Getter methods.
EventThread* getEventThread(const sp<ConnectionHandle>& handle);
+
sp<BnDisplayEventConnection> getEventConnection(const sp<ConnectionHandle>& handle);
// Should be called when receiving a hotplug event.
void hotplugReceived(const sp<ConnectionHandle>& handle, EventThread::DisplayType displayType,
bool connected);
+
// Should be called after the screen is turned on.
void onScreenAcquired(const sp<ConnectionHandle>& handle);
+
// Should be called before the screen is turned off.
void onScreenReleased(const sp<ConnectionHandle>& handle);
+
// Should be called when dumpsys command is received.
void dump(const sp<ConnectionHandle>& handle, String8& result) const;
+
// Offers ability to modify phase offset in the event thread.
void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset);
+ void getDisplayStatInfo(DisplayStatInfo* stats);
+
+ void enableHardwareVsync();
+ void disableHardwareVsync(bool makeUnavailable);
+ void setVsyncPeriod(const nsecs_t period);
+ void addResyncSample(const nsecs_t timestamp);
+ void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
+ void setIgnorePresentFences(bool ignore);
+
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
@@ -84,8 +110,29 @@
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
+ // TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it
+ // should make request to Scheduler to compute next refresh.
+ friend class BufferQueueLayer;
+
+ // If fences from sync Framework are supported.
+ const bool mHasSyncFramework;
+
+ // The offset in nanoseconds to use, when DispSync timestamps present fence
+ // signaling time.
+ const nsecs_t mDispSyncPresentTimeOffset;
+
+ // Each connection has it's own ID. This variable keeps track of the count.
static std::atomic<int64_t> sNextId;
+
+ // Connections are stored in a map <connection ID, connection> for easy retrieval.
std::unordered_map<int64_t, std::unique_ptr<Connection>> mConnections;
+
+ std::mutex mHWVsyncLock;
+ bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock);
+ bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock);
+
+ std::unique_ptr<DispSync> mPrimaryDispSync;
+ std::unique_ptr<EventControlThread> mEventControlThread;
};
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index ea8ca4c..dde0c57 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -39,8 +39,6 @@
nsecs_t app;
};
- enum TransactionStart { EARLY, NORMAL };
-
// Sets the phase offsets
//
// sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
@@ -75,13 +73,14 @@
mSfConnectionHandle = sfConnectionHandle;
}
- void setTransactionStart(TransactionStart transactionStart) {
- if (transactionStart == TransactionStart::EARLY) {
+ void setTransactionStart(Scheduler::TransactionStart transactionStart) {
+ if (transactionStart == Scheduler::TransactionStart::EARLY) {
mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT;
}
// An early transaction stays an early transaction.
- if (transactionStart == mTransactionStart || mTransactionStart == TransactionStart::EARLY) {
+ if (transactionStart == mTransactionStart ||
+ mTransactionStart == Scheduler::TransactionStart::EARLY) {
return;
}
mTransactionStart = transactionStart;
@@ -89,8 +88,8 @@
}
void onTransactionHandled() {
- if (mTransactionStart == TransactionStart::NORMAL) return;
- mTransactionStart = TransactionStart::NORMAL;
+ if (mTransactionStart == Scheduler::TransactionStart::NORMAL) return;
+ mTransactionStart = Scheduler::TransactionStart::NORMAL;
updateOffsets();
}
@@ -138,7 +137,8 @@
}
Offsets getOffsets() {
- if (mTransactionStart == TransactionStart::EARLY || mRemainingEarlyFrameCount > 0) {
+ if (mTransactionStart == Scheduler::TransactionStart::EARLY ||
+ mRemainingEarlyFrameCount > 0) {
return mEarlyOffsets;
} else if (mLastFrameUsedRenderEngine) {
return mEarlyGlOffsets;
@@ -160,7 +160,8 @@
std::atomic<Offsets> mOffsets;
- std::atomic<TransactionStart> mTransactionStart = TransactionStart::NORMAL;
+ std::atomic<Scheduler::TransactionStart> mTransactionStart =
+ Scheduler::TransactionStart::NORMAL;
std::atomic<bool> mLastFrameUsedRenderEngine = false;
std::atomic<int> mRemainingEarlyFrameCount = 0;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 37b32ed..f0723e8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -584,15 +584,14 @@
// start the EventThread
if (mUseScheduler) {
- mScheduler = std::make_unique<Scheduler>();
+ mScheduler = std::make_unique<Scheduler>(
+ [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
mAppConnectionHandle =
- mScheduler->createConnection("appConnection", mPrimaryDispSync.get(),
- SurfaceFlinger::vsyncPhaseOffsetNs,
+ mScheduler->createConnection("appConnection", SurfaceFlinger::vsyncPhaseOffsetNs,
[this] { resyncWithRateLimit(); },
impl::EventThread::InterceptVSyncsCallback());
mSfConnectionHandle =
- mScheduler->createConnection("sfConnection", mPrimaryDispSync.get(),
- SurfaceFlinger::sfVsyncPhaseOffsetNs,
+ mScheduler->createConnection("sfConnection", SurfaceFlinger::sfVsyncPhaseOffsetNs,
[this] { resyncWithRateLimit(); },
[this](nsecs_t timestamp) {
mInterceptor->saveVSyncEvent(timestamp);
@@ -912,10 +911,13 @@
return BAD_VALUE;
}
- // FIXME for now we always return stats for the primary display
- memset(stats, 0, sizeof(*stats));
- stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
- stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
+ // FIXME for now we always return stats for the primary display.
+ if (mUseScheduler) {
+ mScheduler->getDisplayStatInfo(stats);
+ } else {
+ stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+ stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
+ }
return NO_ERROR;
}
@@ -1246,13 +1248,17 @@
const auto activeConfig = getHwComposer().getActiveConfig(displayId);
const nsecs_t period = activeConfig->getVsyncPeriod();
- mPrimaryDispSync->reset();
- mPrimaryDispSync->setPeriod(period);
+ if (mUseScheduler) {
+ mScheduler->setVsyncPeriod(period);
+ } else {
+ mPrimaryDispSync->reset();
+ mPrimaryDispSync->setPeriod(period);
- if (!mPrimaryHWVsyncEnabled) {
- mPrimaryDispSync->beginResync();
- mEventControlThread->setVsyncEnabled(true);
- mPrimaryHWVsyncEnabled = true;
+ if (!mPrimaryHWVsyncEnabled) {
+ mPrimaryDispSync->beginResync();
+ mEventControlThread->setVsyncEnabled(true);
+ mPrimaryHWVsyncEnabled = true;
+ }
}
}
@@ -1300,19 +1306,22 @@
return;
}
- bool needsHwVsync = false;
-
- { // Scope for the lock
- Mutex::Autolock _l(mHWVsyncLock);
- if (mPrimaryHWVsyncEnabled) {
- needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
- }
- }
-
- if (needsHwVsync) {
- enableHardwareVsync();
+ if (mUseScheduler) {
+ mScheduler->addResyncSample(timestamp);
} else {
- disableHardwareVsync(false);
+ bool needsHwVsync = false;
+ { // Scope for the lock
+ Mutex::Autolock _l(mHWVsyncLock);
+ if (mPrimaryHWVsyncEnabled) {
+ needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
+ }
+ }
+
+ if (needsHwVsync) {
+ enableHardwareVsync();
+ } else {
+ disableHardwareVsync(false);
+ }
}
}
@@ -1364,7 +1373,11 @@
// Note: it is assumed the caller holds |mStateLock| when this is called
void SurfaceFlinger::resetDisplayState() {
- disableHardwareVsync(true);
+ if (mUseScheduler) {
+ mScheduler->disableHardwareVsync(true);
+ } else {
+ disableHardwareVsync(true);
+ }
// Clear the drawing state so that the logic inside of
// handleTransactionLocked will fire. It will determine the delta between
// mCurrentState and mDrawingState and re-apply all changes when we make the
@@ -1432,12 +1445,17 @@
// The present fences returned from vr_hwc are not an accurate
// representation of vsync times.
- mPrimaryDispSync->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() ||
- !hasSyncFramework);
+ if (mUseScheduler) {
+ mScheduler->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() || !hasSyncFramework);
+ } else {
+ mPrimaryDispSync->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() ||
+ !hasSyncFramework);
+ }
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
- setCompositorTimingSnapped(0, period, 0);
+ DisplayStatInfo stats{0 /* vsyncTime */, period /* vsyncPeriod */};
+ setCompositorTimingSnapped(stats, 0);
resyncToHardwareVsync(false);
@@ -1736,9 +1754,8 @@
}
}
-void SurfaceFlinger::updateCompositorTiming(
- nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
- std::shared_ptr<FenceTime>& presentFenceTime) {
+void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
+ std::shared_ptr<FenceTime>& presentFenceTime) {
// Update queue of past composite+present times and determine the
// most recently known composite to present latency.
getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime});
@@ -1760,21 +1777,20 @@
getBE().mCompositePresentTimes.pop();
}
- setCompositorTimingSnapped(
- vsyncPhase, vsyncInterval, compositeToPresentLatency);
+ setCompositorTimingSnapped(stats, compositeToPresentLatency);
}
-void SurfaceFlinger::setCompositorTimingSnapped(nsecs_t vsyncPhase,
- nsecs_t vsyncInterval, nsecs_t compositeToPresentLatency) {
+void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats,
+ nsecs_t compositeToPresentLatency) {
// Integer division and modulo round toward 0 not -inf, so we need to
// treat negative and positive offsets differently.
- nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0) ?
- (vsyncInterval - (sfVsyncPhaseOffsetNs % vsyncInterval)) :
- ((-sfVsyncPhaseOffsetNs) % vsyncInterval);
+ nsecs_t idealLatency = (sfVsyncPhaseOffsetNs > 0)
+ ? (stats.vsyncPeriod - (sfVsyncPhaseOffsetNs % stats.vsyncPeriod))
+ : ((-sfVsyncPhaseOffsetNs) % stats.vsyncPeriod);
// Just in case sfVsyncPhaseOffsetNs == -vsyncInterval.
if (idealLatency <= 0) {
- idealLatency = vsyncInterval;
+ idealLatency = stats.vsyncPeriod;
}
// Snap the latency to a value that removes scheduling jitter from the
@@ -1783,15 +1799,14 @@
// something (such as user input) to an accurate diasplay time.
// Snapping also allows an app to precisely calculate sfVsyncPhaseOffsetNs
// with (presentLatency % interval).
- nsecs_t bias = vsyncInterval / 2;
- int64_t extraVsyncs =
- (compositeToPresentLatency - idealLatency + bias) / vsyncInterval;
- nsecs_t snappedCompositeToPresentLatency = (extraVsyncs > 0) ?
- idealLatency + (extraVsyncs * vsyncInterval) : idealLatency;
+ nsecs_t bias = stats.vsyncPeriod / 2;
+ int64_t extraVsyncs = (compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod;
+ nsecs_t snappedCompositeToPresentLatency =
+ (extraVsyncs > 0) ? idealLatency + (extraVsyncs * stats.vsyncPeriod) : idealLatency;
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
- getBE().mCompositorTiming.deadline = vsyncPhase - idealLatency;
- getBE().mCompositorTiming.interval = vsyncInterval;
+ getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency;
+ getBE().mCompositorTiming.interval = stats.vsyncPeriod;
getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
}
@@ -1825,14 +1840,18 @@
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
getBE().mDisplayTimeline.push(presentFenceTime);
- nsecs_t vsyncPhase = mPrimaryDispSync->computeNextRefresh(0);
- nsecs_t vsyncInterval = mPrimaryDispSync->getPeriod();
+ DisplayStatInfo stats;
+ if (mUseScheduler) {
+ mScheduler->getDisplayStatInfo(&stats);
+ } else {
+ stats.vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+ stats.vsyncPeriod = mPrimaryDispSync->getPeriod();
+ }
// We use the mRefreshStartTime which might be sampled a little later than
// when we started doing work for this frame, but that should be okay
// since updateCompositorTiming has snapping logic.
- updateCompositorTiming(
- vsyncPhase, vsyncInterval, mRefreshStartTime, presentFenceTime);
+ updateCompositorTiming(stats, mRefreshStartTime, presentFenceTime);
CompositorTiming compositorTiming;
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -1849,16 +1868,24 @@
});
if (presentFenceTime->isValid()) {
- if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
- enableHardwareVsync();
+ if (mUseScheduler) {
+ mScheduler->addPresentFence(presentFenceTime);
} else {
- disableHardwareVsync(false);
+ if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
+ enableHardwareVsync();
+ } else {
+ disableHardwareVsync(false);
+ }
}
}
if (!hasSyncFramework) {
if (display && getHwComposer().isConnected(display->getId()) && display->isPoweredOn()) {
- enableHardwareVsync();
+ if (mUseScheduler) {
+ mScheduler->enableHardwareVsync();
+ } else {
+ enableHardwareVsync();
+ }
}
}
@@ -1892,7 +1919,7 @@
mHasPoweredOff = false;
} else {
nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
- size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncInterval);
+ size_t numPeriods = static_cast<size_t>(elapsedTime / stats.vsyncPeriod);
if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
getBE().mFrameBuckets[numPeriods] += elapsedTime;
} else {
@@ -3039,7 +3066,8 @@
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (layer->hasReadyFrame()) {
frameQueued = true;
- if (layer->shouldPresentNow(*mPrimaryDispSync)) {
+ const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime();
+ if (layer->shouldPresentNow(expectedPresentTime)) {
mLayersWithQueuedFrames.push_back(layer);
} else {
layer->useEmptyDamage();
@@ -3371,11 +3399,11 @@
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
- return setTransactionFlags(flags, VSyncModulator::TransactionStart::NORMAL);
+ return setTransactionFlags(flags, Scheduler::TransactionStart::NORMAL);
}
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
- VSyncModulator::TransactionStart transactionStart) {
+ Scheduler::TransactionStart transactionStart) {
uint32_t old = mTransactionFlags.fetch_or(flags);
mVsyncModulator.setTransactionStart(transactionStart);
if ((old & flags)==0) { // wake the server up
@@ -3466,9 +3494,8 @@
}
// this triggers the transaction
- const auto start = (flags & eEarlyWakeup)
- ? VSyncModulator::TransactionStart::EARLY
- : VSyncModulator::TransactionStart::NORMAL;
+ const auto start = (flags & eEarlyWakeup) ? Scheduler::TransactionStart::EARLY
+ : Scheduler::TransactionStart::NORMAL;
setTransactionFlags(transactionFlags, start);
// if this is a synchronous transaction, wait for it to take effect
@@ -3991,7 +4018,8 @@
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
- setCompositorTimingSnapped(0, period, 0);
+ DisplayStatInfo stats{0 /* vsyncTime */, period /* vsyncPeriod */};
+ setCompositorTimingSnapped(stats, 0);
}
void SurfaceFlinger::initializeDisplays() {
@@ -4057,8 +4085,11 @@
}
if (display->isPrimary() && currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
- disableHardwareVsync(true); // also cancels any in-progress resync
-
+ if (mUseScheduler) {
+ mScheduler->disableHardwareVsync(true);
+ } else {
+ disableHardwareVsync(true); // also cancels any in-progress resync
+ }
// FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenReleased(mAppConnectionHandle);
@@ -4086,7 +4117,11 @@
} else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
// Leave display going to doze
if (display->isPrimary()) {
- disableHardwareVsync(true); // also cancels any in-progress resync
+ if (mUseScheduler) {
+ mScheduler->disableHardwareVsync(true);
+ } else {
+ disableHardwareVsync(true); // also cancels any in-progress resync
+ }
// FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenReleased(mAppConnectionHandle);
@@ -5033,6 +5068,7 @@
// Needs to be shifted to proper binder interface when we productize
case 1016: {
n = data.readInt32();
+ // TODO(b/113612090): Evaluate if this can be removed.
mPrimaryDispSync->setRefreshSkipCount(n);
return NO_ERROR;
}
@@ -5161,9 +5197,17 @@
}
if ((frequencyScaler.multiplier == 1) && (frequencyScaler.divisor == 1)) {
- enableHardwareVsync();
+ if (mUseScheduler) {
+ mScheduler->enableHardwareVsync();
+ } else {
+ enableHardwareVsync();
+ }
} else {
- disableHardwareVsync(true);
+ if (mUseScheduler) {
+ mScheduler->disableHardwareVsync(true);
+ } else {
+ disableHardwareVsync(true);
+ }
}
mPrimaryDispSync->scalePeriod(frequencyScaler);
getBE().mHwc->setDisplayFrequencyScaleParameters(frequencyScaler);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a0f7c75..f535c4e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -523,7 +523,7 @@
uint32_t peekTransactionFlags();
// Can only be called from the main thread or with mStateLock held
uint32_t setTransactionFlags(uint32_t flags);
- uint32_t setTransactionFlags(uint32_t flags, VSyncModulator::TransactionStart transactionStart);
+ uint32_t setTransactionFlags(uint32_t flags, Scheduler::TransactionStart transactionStart);
void commitTransaction();
bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
uint32_t setClientStateLocked(const ComposerState& composerState);
@@ -662,12 +662,10 @@
void preComposition();
void postComposition();
- void updateCompositorTiming(
- nsecs_t vsyncPhase, nsecs_t vsyncInterval, nsecs_t compositeTime,
- std::shared_ptr<FenceTime>& presentFenceTime);
- void setCompositorTimingSnapped(
- nsecs_t vsyncPhase, nsecs_t vsyncInterval,
- nsecs_t compositeToPresentLatency);
+ void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
+ std::shared_ptr<FenceTime>& presentFenceTime);
+ void setCompositorTimingSnapped(const DisplayStatInfo& stats,
+ nsecs_t compositeToPresentLatency);
void rebuildLayerStacks();
ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& display,
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index d77a324..0bc1c0a 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -32,11 +32,8 @@
namespace android {
TimeStats& TimeStats::getInstance() {
- static std::unique_ptr<TimeStats> sInstance;
- static std::once_flag sOnceFlag;
-
- std::call_once(sOnceFlag, [] { sInstance.reset(new TimeStats); });
- return *sInstance.get();
+ static TimeStats sInstance;
+ return sInstance;
}
void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, size_t& index,
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 34d0fd7..8bd5fcb 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "CredentialsTest.*:LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*"
+ "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*"
}
}
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index df0d982..be91a9c 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -6,8 +6,11 @@
#include <log/log.h>
+#include <mutex>
+
#include "AsyncCallRecorder.h"
#include "Scheduler/DispSync.h"
+#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/Scheduler.h"
#include "mock/MockDispSync.h"
@@ -37,7 +40,7 @@
class MockScheduler : public android::Scheduler {
public:
MockScheduler(std::unique_ptr<EventThread> eventThread)
- : mEventThread(std::move(eventThread)) {}
+ : Scheduler([](bool) {}), mEventThread(std::move(eventThread)) {}
std::unique_ptr<EventThread> makeEventThread(
const std::string& /* connectionName */, DispSync* /* dispSync */,
@@ -81,9 +84,9 @@
EXPECT_CALL(*mEventThread, createEventConnection())
.WillRepeatedly(Return(mEventThreadConnection));
- mConnectionHandle = mScheduler->createConnection("appConnection", mPrimaryDispSync, 16,
- mResyncCallRecorder.getInvocable(),
- mInterceptVSyncCallRecorder.getInvocable());
+ mConnectionHandle =
+ mScheduler->createConnection("appConnection", 16, mResyncCallRecorder.getInvocable(),
+ mInterceptVSyncCallRecorder.getInvocable());
}
SchedulerTest::~SchedulerTest() {
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index 46d6558..495b3f2 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -43,6 +43,7 @@
MOCK_METHOD2(changePhaseOffset, status_t(Callback*, nsecs_t));
MOCK_CONST_METHOD1(computeNextRefresh, nsecs_t(int));
MOCK_METHOD1(setIgnorePresentFences, void(bool));
+ MOCK_METHOD0(expectedPresentTime, nsecs_t());
MOCK_CONST_METHOD1(dump, void(String8&));
};
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 04b9511..c35ddd4 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -16,6 +16,7 @@
"libbase",
"libbinder",
"libcutils",
+ "libgtest_prod",
"libgui",
"liblog",
"libpdx_default_transport",
@@ -27,13 +28,13 @@
cc_library_static {
name: "libbufferhubd",
srcs: [
- "binder/android/dvr/IBufferHub.aidl",
"buffer_channel.cpp",
"buffer_hub.cpp",
"buffer_hub_binder.cpp",
"buffer_node.cpp",
"consumer_channel.cpp",
"consumer_queue_channel.cpp",
+ "IBufferHub.cpp",
"producer_channel.cpp",
"producer_queue_channel.cpp",
],
@@ -48,11 +49,9 @@
static_libs: [
"libbufferhub",
],
- aidl: {
- local_include_dirs: ["binder"],
- include_dirs: ["frameworks/native/aidl/binder"],
- export_aidl_headers: true,
- },
+
+ // TODO(b/117568153): Temporarily opt out using libcrt.
+ no_libcrt: true,
}
cc_binary {
diff --git a/services/vr/bufferhubd/IBufferHub.cpp b/services/vr/bufferhubd/IBufferHub.cpp
new file mode 100644
index 0000000..9d5b91a
--- /dev/null
+++ b/services/vr/bufferhubd/IBufferHub.cpp
@@ -0,0 +1,20 @@
+#include <log/log.h>
+#include <private/dvr/IBufferHub.h>
+
+namespace android {
+namespace dvr {
+
+IMPLEMENT_META_INTERFACE(BufferHub, "android.dvr.IBufferHub");
+
+status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags) {
+ switch (code) {
+ default:
+ // Should not reach
+ ALOGE("onTransact(): unknown code %u received!", code);
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} // namespace dvr
+} // namespace android
\ No newline at end of file
diff --git a/services/vr/bufferhubd/binder/android/dvr/IBufferHub.aidl b/services/vr/bufferhubd/binder/android/dvr/IBufferHub.aidl
deleted file mode 100644
index 6a86adc..0000000
--- a/services/vr/bufferhubd/binder/android/dvr/IBufferHub.aidl
+++ /dev/null
@@ -1,5 +0,0 @@
-package android.dvr;
-
-/** {@hide} */
-interface IBufferHub {
-}
\ No newline at end of file
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
index 6d22dee..dcc6ea4 100644
--- a/services/vr/bufferhubd/buffer_channel.cpp
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -13,11 +13,10 @@
BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
int channel_id, IonBuffer buffer,
- IonBuffer metadata_buffer,
size_t user_metadata_size)
: BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
- buffer_node_(std::make_shared<BufferNode>(
- std::move(buffer), std::move(metadata_buffer), user_metadata_size)),
+ buffer_node_(
+ std::make_shared<BufferNode>(std::move(buffer), user_metadata_size)),
buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
buffer_node_->set_buffer_state_bit(buffer_state_bit_);
}
@@ -85,19 +84,26 @@
}
}
-Status<BufferDescription<BorrowedHandle>> BufferChannel::OnImport(
+Status<BufferTraits<BorrowedHandle>> BufferChannel::OnImport(
Message& /*message*/) {
ATRACE_NAME("BufferChannel::OnImport");
- ALOGD_IF(TRACE, "BufferChannel::OnImport: buffer=%d.",
- buffer_id());
+ ALOGD_IF(TRACE, "BufferChannel::OnImport: buffer=%d.", buffer_id());
- return BufferDescription<BorrowedHandle>{buffer_node_->buffer(),
- buffer_node_->metadata_buffer(),
- buffer_id(),
- channel_id(),
- buffer_state_bit_,
- BorrowedHandle{},
- BorrowedHandle{}};
+ // TODO(b/112057680) Move away from the GraphicBuffer-based IonBuffer.
+ return BufferTraits<BorrowedHandle>{
+ /*buffer_handle=*/buffer_node_->buffer().handle(),
+ /*metadata_handle=*/buffer_node_->metadata().ashmem_handle().Borrow(),
+ /*id=*/buffer_id(),
+ /*buffer_state_bit=*/buffer_state_bit_,
+ /*metadata_size=*/buffer_node_->metadata().metadata_size(),
+ /*width=*/buffer_node_->buffer().width(),
+ /*height=*/buffer_node_->buffer().height(),
+ /*layer_count=*/buffer_node_->buffer().layer_count(),
+ /*format=*/buffer_node_->buffer().format(),
+ /*usage=*/buffer_node_->buffer().usage(),
+ /*stride=*/buffer_node_->buffer().stride(),
+ /*acquire_fence_fd=*/BorrowedHandle{},
+ /*released_fence_fd=*/BorrowedHandle{}};
}
Status<RemoteChannelHandle> BufferChannel::OnDuplicate(
@@ -175,7 +181,17 @@
}
IonBuffer buffer = std::move(buffer_node_->buffer());
- IonBuffer metadata_buffer = std::move(buffer_node_->metadata_buffer());
+ IonBuffer metadata_buffer;
+ if (int ret = metadata_buffer.Alloc(buffer_node_->metadata().metadata_size(),
+ /*height=*/1,
+ /*layer_count=*/1,
+ BufferHubDefs::kMetadataFormat,
+ BufferHubDefs::kMetadataUsage)) {
+ ALOGE("BufferChannel::OnPromote: Failed to allocate metadata: %s",
+ strerror(-ret));
+ return ErrorStatus(EINVAL);
+ }
+
size_t user_metadata_size = buffer_node_->user_metadata_size();
std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
diff --git a/services/vr/bufferhubd/buffer_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp
index def15f1..b507717 100644
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ b/services/vr/bufferhubd/buffer_hub_binder.cpp
@@ -1,33 +1,81 @@
#include <stdio.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <log/log.h>
#include <private/dvr/buffer_hub_binder.h>
namespace android {
namespace dvr {
-status_t BufferHubBinderService::start() {
- ProcessState::self()->startThreadPool();
+status_t BufferHubBinderService::start(
+ const std::shared_ptr<BufferHubService>& pdx_service) {
IPCThreadState::self()->disableBackgroundScheduling(true);
- status_t result = BinderService<BufferHubBinderService>::publish();
- if (result != OK) {
+
+ BufferHubBinderService* service = new BufferHubBinderService();
+ service->pdx_service_ = pdx_service;
+
+ // Not using BinderService::publish because need to get an instance of this
+ // class (above). Following code is the same as
+ // BinderService::publishAndJoinThreadPool
+ sp<IServiceManager> sm = defaultServiceManager();
+ status_t result = sm->addService(
+ String16(getServiceName()), service,
+ /*allowIsolated =*/false,
+ /*dump flags =*/IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
+ if (result != NO_ERROR) {
ALOGE("Publishing bufferhubd failed with error %d", result);
return result;
}
+ sp<ProcessState> process_self(ProcessState::self());
+ process_self->startThreadPool();
+
return result;
}
-status_t BufferHubBinderService::dump(int fd, const Vector<String16> & /* args */) {
- // TODO(b/115435506): not implemented yet
- FILE *out = fdopen(dup(fd), "w");
+status_t BufferHubBinderService::dump(int fd, const Vector<String16>& args) {
+ FILE* out = fdopen(dup(fd), "w");
- fprintf(out, "BufferHubBinderService::dump(): Not Implemented.\n");
+ // Currently not supporting args, so notify the user.
+ if (!args.isEmpty()) {
+ fprintf(out,
+ "Note: dumpsys bufferhubd currently does not support args."
+ "Input arguments are ignored.\n");
+ }
+
+ // TODO(b/116526156): output real data in this class once we have it
+ if (pdx_service_) {
+ // BufferHubService::Dumpstate(size_t) is not actually using the param
+ // So just using 0 as the length
+ fprintf(out, "%s", pdx_service_->DumpState(0).c_str());
+ } else {
+ fprintf(out, "PDX service not registered or died.\n");
+ }
fclose(out);
return NO_ERROR;
}
+sp<IBufferHub> BufferHubBinderService::getServiceProxy() {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> service = sm->checkService(String16(getServiceName()));
+
+ if (service == nullptr) {
+ ALOGE("getServiceProxy(): %s binder service not found!", getServiceName());
+ return nullptr;
+ }
+
+ sp<IBufferHub> ret = interface_cast<IBufferHub>(service);
+ if (ret == nullptr) {
+ ALOGE("getServiceProxy(): %s binder service type casting error!",
+ getServiceName());
+ return nullptr;
+ }
+
+ return ret;
+}
} // namespace dvr
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
index 5a04d0c..782b9c2 100644
--- a/services/vr/bufferhubd/buffer_node.cpp
+++ b/services/vr/bufferhubd/buffer_node.cpp
@@ -4,26 +4,15 @@
namespace android {
namespace dvr {
-BufferNode::BufferNode(IonBuffer buffer, IonBuffer metadata_buffer,
- size_t user_metadata_size)
- : buffer_(std::move(buffer)),
- metadata_buffer_(std::move(metadata_buffer)),
- user_metadata_size_(user_metadata_size) {}
+BufferNode::BufferNode(IonBuffer buffer, size_t user_metadata_size)
+ : buffer_(std::move(buffer)) {
+ metadata_ = BufferHubMetadata::Create(user_metadata_size);
+}
// 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)
- : user_metadata_size_(user_metadata_size) {
- // The size the of metadata buffer is used as the "width" parameter during
- // allocation. Thus it cannot overflow uint32_t.
- if (user_metadata_size_ >= (std::numeric_limits<uint32_t>::max() -
- BufferHubDefs::kMetadataHeaderSize)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: metadata size too big.");
- return;
- }
-
+ size_t user_metadata_size) {
if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
ALOGE(
"DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
@@ -32,20 +21,7 @@
return;
}
- // Buffer metadata has two parts: 1) a fixed sized metadata header; and 2)
- // user requested metadata.
- const size_t size = BufferHubDefs::kMetadataHeaderSize + user_metadata_size_;
- if (int ret = metadata_buffer_.Alloc(size,
- /*height=*/1,
- /*layer_count=*/1,
- BufferHubDefs::kMetadataFormat,
- BufferHubDefs::kMetadataUsage)) {
- ALOGE(
- "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
- "metadata: %s",
- strerror(-ret));
- return;
- }
+ metadata_ = BufferHubMetadata::Create(user_metadata_size);
}
} // namespace dvr
diff --git a/services/vr/bufferhubd/bufferhubd.cpp b/services/vr/bufferhubd/bufferhubd.cpp
index 0ca7edc..3e10b26 100644
--- a/services/vr/bufferhubd/bufferhubd.cpp
+++ b/services/vr/bufferhubd/bufferhubd.cpp
@@ -10,7 +10,7 @@
int main(int, char**) {
int ret = -1;
- std::shared_ptr<android::pdx::Service> service;
+ std::shared_ptr<android::dvr::BufferHubService> pdx_service;
std::unique_ptr<android::pdx::ServiceDispatcher> dispatcher;
// We need to be able to create endpoints with full perms.
@@ -33,15 +33,16 @@
else
ALOGI("New nofile limit is %llu/%llu.", rlim.rlim_cur, rlim.rlim_max);
- CHECK_ERROR(android::dvr::BufferHubBinderService::start() != android::OK,
- error, "Failed to create bufferhub binder service\n");
-
dispatcher = android::pdx::ServiceDispatcher::Create();
CHECK_ERROR(!dispatcher, error, "Failed to create service dispatcher\n");
- service = android::dvr::BufferHubService::Create();
- CHECK_ERROR(!service, error, "Failed to create bufferhubd service\n");
- dispatcher->AddService(service);
+ pdx_service = android::dvr::BufferHubService::Create();
+ CHECK_ERROR(!pdx_service, error, "Failed to create bufferhub pdx service\n");
+ dispatcher->AddService(pdx_service);
+
+ ret = android::dvr::BufferHubBinderService::start(pdx_service);
+ CHECK_ERROR(ret != android::NO_ERROR, error,
+ "Failed to create bufferhub binder service\n");
ret = dvrSetSchedulerClass(0, "graphics");
CHECK_ERROR(ret < 0, error, "Failed to set thread priority");
diff --git a/services/vr/bufferhubd/consumer_channel.cpp b/services/vr/bufferhubd/consumer_channel.cpp
index 623c9d6..4ff7adf 100644
--- a/services/vr/bufferhubd/consumer_channel.cpp
+++ b/services/vr/bufferhubd/consumer_channel.cpp
@@ -90,11 +90,6 @@
*this, &ConsumerChannel::OnConsumerRelease, message);
return true;
- case BufferHubRPC::ConsumerSetIgnore::Opcode:
- DispatchRemoteMethod<BufferHubRPC::ConsumerSetIgnore>(
- *this, &ConsumerChannel::OnConsumerSetIgnore, message);
- return true;
-
default:
return false;
}
@@ -120,9 +115,8 @@
if (acquired_ || released_) {
ALOGE(
"ConsumerChannel::OnConsumerAcquire: Acquire when not posted: "
- "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d",
- ignored_, acquired_, released_, message.GetChannelId(),
- producer->buffer_id());
+ "acquired=%d released=%d channel_id=%d buffer_id=%d",
+ acquired_, released_, message.GetChannelId(), producer->buffer_id());
return ErrorStatus(EBUSY);
} else {
auto status = producer->OnConsumerAcquire(message);
@@ -144,9 +138,8 @@
if (!acquired_ || released_) {
ALOGE(
"ConsumerChannel::OnConsumerRelease: Release when not acquired: "
- "ignored=%d acquired=%d released=%d channel_id=%d buffer_id=%d",
- ignored_, acquired_, released_, message.GetChannelId(),
- producer->buffer_id());
+ "acquired=%d released=%d channel_id=%d buffer_id=%d",
+ acquired_, released_, message.GetChannelId(), producer->buffer_id());
return ErrorStatus(EBUSY);
} else {
auto status =
@@ -160,36 +153,11 @@
}
}
-Status<void> ConsumerChannel::OnConsumerSetIgnore(Message&, bool ignored) {
- ATRACE_NAME("ConsumerChannel::OnConsumerSetIgnore");
- auto producer = GetProducer();
- if (!producer)
- return ErrorStatus(EPIPE);
-
- ignored_ = ignored;
- if (ignored_ && acquired_) {
- // Update the producer if ignore is set after the consumer acquires the
- // buffer.
- ClearAvailable();
- producer->OnConsumerIgnored();
- acquired_ = false;
- released_ = true;
- }
-
- return {};
-}
-
bool ConsumerChannel::OnProducerPosted() {
- if (ignored_) {
- acquired_ = false;
- released_ = true;
- return false;
- } else {
- acquired_ = false;
- released_ = false;
- SignalAvailable();
- return true;
- }
+ acquired_ = false;
+ released_ = false;
+ SignalAvailable();
+ return true;
}
void ConsumerChannel::OnProducerClosed() {
diff --git a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
new file mode 100644
index 0000000..266ae88
--- /dev/null
+++ b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
@@ -0,0 +1,30 @@
+#ifndef ANDROID_DVR_IBUFFERHUB_H
+#define ANDROID_DVR_IBUFFERHUB_H
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+namespace dvr {
+
+class IBufferHub : public IInterface {
+ public:
+ DECLARE_META_INTERFACE(BufferHub);
+};
+
+class BnBufferHub : public BnInterface<IBufferHub> {
+ public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+};
+
+class BpBufferHub : public BpInterface<IBufferHub> {
+ public:
+ explicit BpBufferHub(const sp<IBinder>& impl)
+ : BpInterface<IBufferHub>(impl) {}
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
index bcc93a1..1697251 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_channel.h
@@ -4,6 +4,7 @@
#include <pdx/channel_handle.h>
#include <pdx/file_handle.h>
#include <private/dvr/buffer_hub.h>
+#include <private/dvr/buffer_hub_defs.h>
#include <private/dvr/buffer_node.h>
namespace android {
@@ -34,8 +35,7 @@
private:
// Creates a detached buffer from existing IonBuffers.
BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
- IonBuffer buffer, IonBuffer metadata_buffer,
- size_t user_metadata_size);
+ IonBuffer buffer, size_t user_metadata_size);
// Allocates a new detached buffer.
BufferChannel(BufferHubService* service, int buffer_id, uint32_t width,
@@ -47,7 +47,7 @@
std::shared_ptr<BufferNode> buffer_node,
uint64_t buffer_state_bit);
- pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
+ pdx::Status<BufferTraits<pdx::BorrowedHandle>> OnImport(
pdx::Message& message);
pdx::Status<pdx::RemoteChannelHandle> OnDuplicate(pdx::Message& message);
pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
index c0281fd..e266ff8 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
@@ -2,22 +2,29 @@
#define ANDROID_DVR_BUFFER_HUB_BINDER_H
#include <binder/BinderService.h>
-
-#include "android/dvr/BnBufferHub.h"
+#include <private/dvr/IBufferHub.h>
+#include <private/dvr/buffer_hub.h>
namespace android {
namespace dvr {
-class BufferHubBinderService : public BinderService<BufferHubBinderService>, public BnBufferHub {
+class BufferHubBinderService : public BinderService<BufferHubBinderService>,
+ public BnBufferHub {
public:
- static status_t start();
+ static status_t start(const std::shared_ptr<BufferHubService>& pdx_service);
static const char* getServiceName() { return "bufferhubd"; }
// Dump bufferhub related information to given fd (usually stdout)
// usage: adb shell dumpsys bufferhubd
- virtual status_t dump(int fd, const Vector<String16> &args) override;
+ virtual status_t dump(int fd, const Vector<String16>& args) override;
+
+ // Helper function to get the BpReference to this service
+ static sp<IBufferHub> getServiceProxy();
+
+ private:
+ std::shared_ptr<BufferHubService> pdx_service_;
};
} // namespace dvr
} // namespace android
-#endif // ANDROID_DVR_BUFFER_HUB_BINDER_H
\ No newline at end of file
+#endif // ANDROID_DVR_BUFFER_HUB_BINDER_H
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_node.h b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
index 4bcf4e3..d6c6105 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_node.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_node.h
@@ -2,6 +2,7 @@
#define ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
#include <private/dvr/ion_buffer.h>
+#include <ui/BufferHubMetadata.h>
namespace android {
namespace dvr {
@@ -10,39 +11,32 @@
public:
// Creates a BufferNode from existing IonBuffers, i.e. creating from an
// existing ProducerChannel.
- BufferNode(IonBuffer buffer, IonBuffer metadata_buffer,
- size_t user_metadata_size);
+ BufferNode(IonBuffer buffer, size_t user_metadata_size);
// 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);
// Returns whether the object holds a valid graphic buffer.
- bool IsValid() const {
- return buffer_.IsValid() && metadata_buffer_.IsValid();
- }
+ bool IsValid() const { return buffer_.IsValid() && metadata_.IsValid(); }
- size_t user_metadata_size() const { return user_metadata_size_; }
+ size_t user_metadata_size() const { return metadata_.user_metadata_size(); }
uint64_t active_buffer_bit_mask() const { return active_buffer_bit_mask_; }
void set_buffer_state_bit(uint64_t buffer_state_bit) {
active_buffer_bit_mask_ |= buffer_state_bit;
}
- // Used to take out IonBuffers.
+ // Accessor of the IonBuffer.
IonBuffer& buffer() { return buffer_; }
- IonBuffer& metadata_buffer() { return metadata_buffer_; }
-
- // Used to access IonBuffers.
const IonBuffer& buffer() const { return buffer_; }
- const IonBuffer& metadata_buffer() const { return metadata_buffer_; }
+
+ // Accessor of the metadata.
+ const BufferHubMetadata& metadata() const { return metadata_; }
private:
// Gralloc buffer handles.
IonBuffer buffer_;
- IonBuffer metadata_buffer_;
-
- // Size of user requested metadata.
- const size_t user_metadata_size_;
+ BufferHubMetadata metadata_;
// All active buffer bits. Valid bits are the lower 63 bits, while the
// highest bit is reserved for the exclusive writing and should not be set.
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
index 0d70409..84f664d 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_channel.h
@@ -37,12 +37,10 @@
pdx::Status<LocalFence> OnConsumerAcquire(Message& message);
pdx::Status<void> OnConsumerRelease(Message& message,
LocalFence release_fence);
- pdx::Status<void> OnConsumerSetIgnore(Message& message, bool ignore);
uint64_t consumer_state_bit_{0};
bool acquired_{false};
bool released_{true};
- bool ignored_{false}; // True if we are ignoring events.
std::weak_ptr<Channel> producer_;
ConsumerChannel(const ConsumerChannel&) = delete;
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index 242198f..18bb7bf 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -8,8 +8,8 @@
#include <pdx/channel_handle.h>
#include <pdx/file_handle.h>
#include <pdx/rpc/buffer_wrapper.h>
-#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/buffer_hub.h>
+#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/ion_buffer.h>
namespace android {
@@ -58,7 +58,7 @@
pdx::Status<void> OnConsumerRelease(Message& message,
LocalFence release_fence);
- void OnConsumerIgnored();
+ void DecrementPendingConsumers();
void OnConsumerOrphaned(ConsumerChannel* channel);
void AddConsumer(ConsumerChannel* channel);
@@ -81,10 +81,8 @@
BufferHubDefs::MetadataHeader* metadata_header_ = nullptr;
std::atomic<uint64_t>* buffer_state_ = nullptr;
std::atomic<uint64_t>* fence_state_ = nullptr;
+ std::atomic<uint64_t>* active_clients_bit_mask_ = nullptr;
- // All active consumer bits. Valid bits are the lower 63 bits, while the
- // highest bit is reserved for the producer and should not be set.
- uint64_t active_consumer_bit_mask_{0ULL};
// All orphaned consumer bits. Valid bits are the lower 63 bits, while the
// highest bit is reserved for the producer and should not be set.
uint64_t orphaned_consumer_bit_mask_{0ULL};
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 057d4f4..581390f 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -7,8 +7,8 @@
#include <thread>
#include <log/log.h>
-#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/buffer_channel.h>
+#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/consumer_channel.h>
#include <private/dvr/producer_channel.h>
#include <sync/sync.h>
@@ -96,8 +96,9 @@
// and also initialize the value to zero.
buffer_state_ =
new (&metadata_header_->buffer_state) std::atomic<uint64_t>(0);
- fence_state_ =
- new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
+ fence_state_ = new (&metadata_header_->fence_state) std::atomic<uint64_t>(0);
+ active_clients_bit_mask_ =
+ new (&metadata_header_->active_clients_bit_mask) std::atomic<uint64_t>(0);
acquire_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
release_fence_fd_.Reset(epoll_create1(EPOLL_CLOEXEC));
@@ -261,8 +262,12 @@
// Try find the next consumer state bit which has not been claimed by any
// consumer yet.
+ // memory_order_acquire is chosen here because all writes in other threads
+ // that release active_clients_bit_mask_ need to be visible here.
+ uint64_t current_active_clients_bit_mask =
+ active_clients_bit_mask_->load(std::memory_order_acquire);
uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
- active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
+ current_active_clients_bit_mask | orphaned_consumer_bit_mask_ |
BufferHubDefs::kProducerStateBit);
if (consumer_state_bit == 0ULL) {
ALOGE(
@@ -271,6 +276,23 @@
return ErrorStatus(E2BIG);
}
+ uint64_t updated_active_clients_bit_mask =
+ current_active_clients_bit_mask | consumer_state_bit;
+ // Set the updated value only if the current value stays the same as what was
+ // read before. If the comparison succeeds, update the value without
+ // reordering anything before or after this read-modify-write in the current
+ // thread, and the modification will be visible in other threads that acquire
+ // active_clients_bit_mask_. If the comparison fails, load the result of
+ // all writes from all threads to updated_active_clients_bit_mask.
+ if (!active_clients_bit_mask_->compare_exchange_weak(
+ current_active_clients_bit_mask, updated_active_clients_bit_mask,
+ std::memory_order_acq_rel, std::memory_order_acquire)) {
+ ALOGE("Current active clients bit mask is changed to %" PRIu64
+ ", which was expected to be %" PRIu64 ".",
+ updated_active_clients_bit_mask, current_active_clients_bit_mask);
+ return ErrorStatus(EBUSY);
+ }
+
auto consumer =
std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
consumer_state_bit, shared_from_this());
@@ -280,6 +302,10 @@
"ProducerChannel::CreateConsumer: failed to set new consumer channel: "
"%s",
channel_status.GetErrorMessage().c_str());
+ // Restore the consumer state bit and make it visible in other threads that
+ // acquire the active_clients_bit_mask_.
+ active_clients_bit_mask_->fetch_and(~consumer_state_bit,
+ std::memory_order_release);
return ErrorStatus(ENOMEM);
}
@@ -290,7 +316,6 @@
pending_consumers_++;
}
- active_consumer_bit_mask_ |= consumer_state_bit;
return {status.take()};
}
@@ -300,8 +325,8 @@
return CreateConsumer(message);
}
-Status<void> ProducerChannel::OnProducerPost(
- Message&, LocalFence acquire_fence) {
+Status<void> ProducerChannel::OnProducerPost(Message&,
+ LocalFence acquire_fence) {
ATRACE_NAME("ProducerChannel::OnProducerPost");
ALOGD_IF(TRACE, "ProducerChannel::OnProducerPost: buffer_id=%d", buffer_id());
if (!producer_owns_) {
@@ -315,9 +340,9 @@
int ret = epoll_ctl(release_fence_fd_.Get(), EPOLL_CTL_MOD,
dummy_fence_fd_.Get(), &event);
ALOGE_IF(ret < 0,
- "ProducerChannel::OnProducerPost: Failed to modify the shared "
- "release fence to include the dummy fence: %s",
- strerror(errno));
+ "ProducerChannel::OnProducerPost: Failed to modify the shared "
+ "release fence to include the dummy fence: %s",
+ strerror(errno));
eventfd_t dummy_fence_count = 0ULL;
if (eventfd_read(dummy_fence_fd_.Get(), &dummy_fence_count) < 0) {
@@ -410,9 +435,9 @@
return ErrorStatus(-ret);
};
- std::unique_ptr<BufferChannel> channel = BufferChannel::Create(
- service(), buffer_id(), channel_id, std::move(buffer_),
- std::move(metadata_buffer_), user_metadata_size_);
+ std::unique_ptr<BufferChannel> channel =
+ BufferChannel::Create(service(), buffer_id(), channel_id,
+ std::move(buffer_), user_metadata_size_);
if (!channel) {
ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
return ErrorStatus(EINVAL);
@@ -474,7 +499,7 @@
}
}
- OnConsumerIgnored();
+ DecrementPendingConsumers();
if (pending_consumers_ == 0) {
// Clear the producer bit atomically to transit into released state. This
// has to done by BufferHub as it requries synchronization among all
@@ -507,21 +532,22 @@
return {};
}
-void ProducerChannel::OnConsumerIgnored() {
+void ProducerChannel::DecrementPendingConsumers() {
if (pending_consumers_ == 0) {
- ALOGE("ProducerChannel::OnConsumerIgnored: no pending consumer.");
+ ALOGE("ProducerChannel::DecrementPendingConsumers: no pending consumer.");
return;
}
--pending_consumers_;
ALOGD_IF(TRACE,
- "ProducerChannel::OnConsumerIgnored: buffer_id=%d %d consumers left",
+ "ProducerChannel::DecrementPendingConsumers: buffer_id=%d %d "
+ "consumers left",
buffer_id(), pending_consumers_);
}
void ProducerChannel::OnConsumerOrphaned(ConsumerChannel* channel) {
// Ignore the orphaned consumer.
- OnConsumerIgnored();
+ DecrementPendingConsumers();
const uint64_t consumer_state_bit = channel->consumer_state_bit();
ALOGE_IF(orphaned_consumer_bit_mask_ & consumer_state_bit,
@@ -551,7 +577,10 @@
void ProducerChannel::RemoveConsumer(ConsumerChannel* channel) {
consumer_channels_.erase(
std::find(consumer_channels_.begin(), consumer_channels_.end(), channel));
- active_consumer_bit_mask_ &= ~channel->consumer_state_bit();
+ // Restore the consumer state bit and make it visible in other threads that
+ // acquire the active_clients_bit_mask_.
+ active_clients_bit_mask_->fetch_and(~channel->consumer_state_bit(),
+ std::memory_order_release);
const uint64_t buffer_state = buffer_state_->load();
if (BufferHubDefs::IsBufferPosted(buffer_state) ||
diff --git a/services/vr/bufferhubd/tests/Android.bp b/services/vr/bufferhubd/tests/Android.bp
index 4d1d43f..bf8ea5b 100644
--- a/services/vr/bufferhubd/tests/Android.bp
+++ b/services/vr/bufferhubd/tests/Android.bp
@@ -6,11 +6,21 @@
"-DTRACE=0",
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
],
- static_libs: ["libbufferhubd"],
+ header_libs: ["libdvr_headers"],
+ static_libs: [
+ "libbufferhub",
+ "libbufferhubd",
+ "libgmock",
+ ],
shared_libs: [
"libbase",
"libbinder",
"liblog",
+ "libpdx_default_transport",
+ "libui",
"libutils",
],
+
+ // TODO(b/117568153): Temporarily opt out using libcrt.
+ no_libcrt: true,
}
\ No newline at end of file
diff --git a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
index e3f2825..587e6db 100644
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
@@ -1,19 +1,23 @@
-#include <private/dvr/buffer_hub_binder.h>
-
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <private/dvr/buffer_hub_binder.h>
namespace android {
namespace dvr {
namespace {
+using testing::Ne;
+
class BufferHubBinderServiceTest : public ::testing::Test {
// Add setup and teardown if necessary
};
TEST_F(BufferHubBinderServiceTest, TestInitialize) {
- // Test if start binder server returns OK
- EXPECT_EQ(BufferHubBinderService::start(), OK);
+ // Create a new service will kill the current one.
+ // So just check if Binder service is running
+ sp<IBufferHub> service = BufferHubBinderService::getServiceProxy();
+ EXPECT_THAT(service, Ne(nullptr));
}
} // namespace
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index fa63fbd..5722810 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 85
+define VERSION_PATCH 86
// API limits
define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -45,6 +45,10 @@
define VK_QUEUE_FAMILY_EXTERNAL -2
@extension("VK_EXT_queue_family_foreign")
define VK_QUEUE_FAMILY_FOREIGN_EXT -3
+@extension("VK_MAX_DRIVER_NAME_SIZE_KHR") // 197
+define VK_MAX_DRIVER_NAME_SIZE_KHR 256
+@extension("VK_MAX_DRIVER_NAME_SIZE_KHR") // 197
+define VK_MAX_DRIVER_INFO_SIZE_KHR 256
// API keywords
define VK_TRUE 1
@@ -545,6 +549,10 @@
@extension("VK_AMD_buffer_marker") define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1
@extension("VK_AMD_buffer_marker") define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker"
+// 181
+@extension("VK_KHR_shader_atomic_int64") define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1
+@extension("VK_KHR_shader_atomic_int64") define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64"
+
// 186
@extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1
@extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties"
@@ -553,6 +561,10 @@
@extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
@extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
+// 197
+@extension("VK_KHR_driver_properties") define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1
+@extension("VK_KHR_driver_properties") define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties"
+
// 199
@extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1
@extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned"
@@ -1763,6 +1775,12 @@
VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002,
+ //@extension("VK_KHR_shader_atomic_int64") // 181
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000,
+
+ //@extension("VK_KHR_driver_properties") // 197
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000,
+
//@extension("VK_AMD_shader_core_properties") // 186
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
@@ -2264,6 +2282,19 @@
VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024,
}
+@extension("VK_KHR_driver_properties") // 197
+enum VkDriverIdKHR {
+ VK_DRIVER_ID_AMD_PROPRIETARY_KHR = 1,
+ VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = 2,
+ VK_DRIVER_ID_MESA_RADV_KHR = 3,
+ VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = 4,
+ VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = 5,
+ VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = 6,
+ VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = 7,
+ VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = 8,
+ VK_DRIVER_ID_ARM_PROPRIETARY_KHR = 9,
+}
+
/////////////////
// Bitfields //
/////////////////
@@ -7214,6 +7245,14 @@
VkDeviceSize minImportedHostPointerAlignment
}
+@extension("VK_KHR_shader_atomic_int64") // 181
+class VkPhysicalDeviceShaderAtomicInt64FeaturesKHR {
+ VkStructureType sType
+ void* pNext
+ VkBool32 shaderBufferInt64Atomics
+ VkBool32 shaderSharedInt64Atomics
+}
+
@extension("VK_AMD_shader_core_properties") // 186
class VkPhysicalDeviceShaderCorePropertiesAMD {
VkStructureType sType
@@ -7263,6 +7302,24 @@
VkBool32 vertexAttributeInstanceRateZeroDivisor
}
+@extension("VK_KHR_driver_properties") // 197
+class VkConformanceVersionKHR {
+ u8 major
+ u8 minor
+ u8 subminor
+ u8 patch
+}
+
+@extension("VK_KHR_driver_properties") // 197
+class VkPhysicalDeviceDriverPropertiesKHR {
+ VkStructureType sType
+ void* pNext
+ u32 driverID
+ char[VK_MAX_DRIVER_NAME_SIZE_KHR] driverName
+ char[VK_MAX_DRIVER_INFO_SIZE_KHR] driverInfo
+ VkConformanceVersionKHR conformanceVersion
+}
+
@extension("VK_NV_compute_shader_derivatives") // 202
class VkPhysicalDeviceComputeShaderDerivativesFeaturesNV {
VkStructureType sType
@@ -11168,42 +11225,42 @@
@extension("VK_NVX_raytracing") // 166
cmd void vkCmdBuildAccelerationStructureNVX(
- VkCommandBuffer cmdBuf,
- VkAccelerationStructureTypeNVX type,
- u32 instanceCount,
- VkBuffer instanceData,
- VkDeviceSize instanceOffset,
- u32 geometryCount,
- const VkGeometryNVX* pGeometries,
- VkBuildAccelerationStructureFlagsNVX flags,
- VkBool32 update,
- VkAccelerationStructureNVX dst,
- VkAccelerationStructureNVX src,
- VkBuffer scratch,
- VkDeviceSize scratchOffset) {
+ VkCommandBuffer commandBuffer,
+ VkAccelerationStructureTypeNVX type,
+ u32 instanceCount,
+ VkBuffer instanceData,
+ VkDeviceSize instanceOffset,
+ u32 geometryCount,
+ const VkGeometryNVX* pGeometries,
+ VkBuildAccelerationStructureFlagsNVX flags,
+ VkBool32 update,
+ VkAccelerationStructureNVX dst,
+ VkAccelerationStructureNVX src,
+ VkBuffer scratch,
+ VkDeviceSize scratchOffset) {
}
@extension("VK_NVX_raytracing") // 166
cmd void vkCmdCopyAccelerationStructureNVX(
- VkCommandBuffer cmdBuf,
- VkAccelerationStructureNVX dst,
- VkAccelerationStructureNVX src,
- VkCopyAccelerationStructureModeNVX mode) {
+ VkCommandBuffer commandBuffer,
+ VkAccelerationStructureNVX dst,
+ VkAccelerationStructureNVX src,
+ VkCopyAccelerationStructureModeNVX mode) {
}
@extension("VK_NVX_raytracing") // 166
cmd void vkCmdTraceRaysNVX(
- VkCommandBuffer cmdBuf,
- VkBuffer raygenShaderBindingTableBuffer,
- VkDeviceSize raygenShaderBindingOffset,
- VkBuffer missShaderBindingTableBuffer,
- VkDeviceSize missShaderBindingOffset,
- VkDeviceSize missShaderBindingStride,
- VkBuffer hitShaderBindingTableBuffer,
- VkDeviceSize hitShaderBindingOffset,
- VkDeviceSize hitShaderBindingStride,
- u32 width,
- u32 height) {
+ VkCommandBuffer commandBuffer,
+ VkBuffer raygenShaderBindingTableBuffer,
+ VkDeviceSize raygenShaderBindingOffset,
+ VkBuffer missShaderBindingTableBuffer,
+ VkDeviceSize missShaderBindingOffset,
+ VkDeviceSize missShaderBindingStride,
+ VkBuffer hitShaderBindingTableBuffer,
+ VkDeviceSize hitShaderBindingOffset,
+ VkDeviceSize hitShaderBindingStride,
+ u32 width,
+ u32 height) {
}
@extension("VK_NVX_raytracing") // 166
@@ -11219,38 +11276,38 @@
@extension("VK_NVX_raytracing") // 166
cmd VkResult vkGetRaytracingShaderHandlesNVX(
- VkDevice device,
- VkPipeline pipeline,
- u32 firstGroup,
- u32 groupCount,
- platform.size_t dataSize,
- void* pData) {
+ VkDevice device,
+ VkPipeline pipeline,
+ u32 firstGroup,
+ u32 groupCount,
+ platform.size_t dataSize,
+ void* pData) {
return ?
}
@extension("VK_NVX_raytracing") // 166
cmd VkResult vkGetAccelerationStructureHandleNVX(
- VkDevice device,
- VkAccelerationStructureNVX accelerationStructure,
- platform.size_t dataSize,
- void* pData) {
+ VkDevice device,
+ VkAccelerationStructureNVX accelerationStructure,
+ platform.size_t dataSize,
+ void* pData) {
return ?
}
@extension("VK_NVX_raytracing") // 166
cmd void vkCmdWriteAccelerationStructurePropertiesNVX(
- VkCommandBuffer cmdBuf,
- VkAccelerationStructureNVX accelerationStructure,
- VkQueryType queryType,
- VkQueryPool queryPool,
- u32 query) {
+ VkCommandBuffer commandBuffer,
+ VkAccelerationStructureNVX accelerationStructure,
+ VkQueryType queryType,
+ VkQueryPool queryPool,
+ u32 query) {
}
@extension("VK_NVX_raytracing") // 166
cmd VkResult vkCompileDeferredNVX(
- VkDevice device,
- VkPipeline pipeline,
- u32 shader) {
+ VkDevice device,
+ VkPipeline pipeline,
+ u32 shader) {
return ?
}
diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h
index 2d1b3f5..39f4dc6 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 85
+#define VK_HEADER_VERSION 86
#define VK_NULL_HANDLE 0
@@ -427,10 +427,12 @@
VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000,
VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000,
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000,
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001,
@@ -6044,6 +6046,60 @@
+#define VK_KHR_shader_atomic_int64 1
+#define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1
+#define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64"
+
+typedef struct VkPhysicalDeviceShaderAtomicInt64FeaturesKHR {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 shaderBufferInt64Atomics;
+ VkBool32 shaderSharedInt64Atomics;
+} VkPhysicalDeviceShaderAtomicInt64FeaturesKHR;
+
+
+
+#define VK_KHR_driver_properties 1
+#define VK_MAX_DRIVER_NAME_SIZE_KHR 256
+#define VK_MAX_DRIVER_INFO_SIZE_KHR 256
+#define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1
+#define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties"
+
+
+typedef enum VkDriverIdKHR {
+ VK_DRIVER_ID_AMD_PROPRIETARY_KHR = 1,
+ VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = 2,
+ VK_DRIVER_ID_MESA_RADV_KHR = 3,
+ VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = 4,
+ VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = 5,
+ VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = 6,
+ VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = 7,
+ VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = 8,
+ VK_DRIVER_ID_ARM_PROPRIETARY_KHR = 9,
+ 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_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkDriverIdKHR;
+
+typedef struct VkConformanceVersionKHR {
+ uint8_t major;
+ uint8_t minor;
+ uint8_t subminor;
+ uint8_t patch;
+} VkConformanceVersionKHR;
+
+typedef struct VkPhysicalDeviceDriverPropertiesKHR {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t driverID;
+ char driverName[VK_MAX_DRIVER_NAME_SIZE_KHR];
+ char driverInfo[VK_MAX_DRIVER_INFO_SIZE_KHR];
+ VkConformanceVersionKHR conformanceVersion;
+} VkPhysicalDeviceDriverPropertiesKHR;
+
+
+
#define VK_KHR_vulkan_memory_model 1
#define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2
#define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model"
@@ -8044,13 +8100,13 @@
typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
typedef void (VKAPI_PTR *PFN_vkGetAccelerationStructureScratchMemoryRequirementsNVX)(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNVX* pInfo, VkMemoryRequirements2KHR* pMemoryRequirements);
typedef VkResult (VKAPI_PTR *PFN_vkBindAccelerationStructureMemoryNVX)(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos);
-typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNVX)(VkCommandBuffer cmdBuf, VkAccelerationStructureTypeNVX type, uint32_t instanceCount, VkBuffer instanceData, VkDeviceSize instanceOffset, uint32_t geometryCount, const VkGeometryNVX* pGeometries, VkBuildAccelerationStructureFlagsNVX flags, VkBool32 update, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkBuffer scratch, VkDeviceSize scratchOffset);
-typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNVX)(VkCommandBuffer cmdBuf, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkCopyAccelerationStructureModeNVX mode);
-typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNVX)(VkCommandBuffer cmdBuf, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, uint32_t width, uint32_t height);
+typedef void (VKAPI_PTR *PFN_vkCmdBuildAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureTypeNVX type, uint32_t instanceCount, VkBuffer instanceData, VkDeviceSize instanceOffset, uint32_t geometryCount, const VkGeometryNVX* pGeometries, VkBuildAccelerationStructureFlagsNVX flags, VkBool32 update, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkBuffer scratch, VkDeviceSize scratchOffset);
+typedef void (VKAPI_PTR *PFN_vkCmdCopyAccelerationStructureNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX dst, VkAccelerationStructureNVX src, VkCopyAccelerationStructureModeNVX mode);
+typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysNVX)(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, VkDeviceSize hitShaderBindingStride, uint32_t width, uint32_t height);
typedef VkResult (VKAPI_PTR *PFN_vkCreateRaytracingPipelinesNVX)(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRaytracingPipelineCreateInfoNVX* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines);
typedef VkResult (VKAPI_PTR *PFN_vkGetRaytracingShaderHandlesNVX)(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void* pData);
typedef VkResult (VKAPI_PTR *PFN_vkGetAccelerationStructureHandleNVX)(VkDevice device, VkAccelerationStructureNVX accelerationStructure, size_t dataSize, void* pData);
-typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructurePropertiesNVX)(VkCommandBuffer cmdBuf, VkAccelerationStructureNVX accelerationStructure, VkQueryType queryType, VkQueryPool queryPool, uint32_t query);
+typedef void (VKAPI_PTR *PFN_vkCmdWriteAccelerationStructurePropertiesNVX)(VkCommandBuffer commandBuffer, VkAccelerationStructureNVX accelerationStructure, VkQueryType queryType, VkQueryPool queryPool, uint32_t query);
typedef VkResult (VKAPI_PTR *PFN_vkCompileDeferredNVX)(VkDevice device, VkPipeline pipeline, uint32_t shader);
#ifndef VK_NO_PROTOTYPES
@@ -8081,7 +8137,7 @@
const VkBindAccelerationStructureMemoryInfoNVX* pBindInfos);
VKAPI_ATTR void VKAPI_CALL vkCmdBuildAccelerationStructureNVX(
- VkCommandBuffer cmdBuf,
+ VkCommandBuffer commandBuffer,
VkAccelerationStructureTypeNVX type,
uint32_t instanceCount,
VkBuffer instanceData,
@@ -8096,13 +8152,13 @@
VkDeviceSize scratchOffset);
VKAPI_ATTR void VKAPI_CALL vkCmdCopyAccelerationStructureNVX(
- VkCommandBuffer cmdBuf,
+ VkCommandBuffer commandBuffer,
VkAccelerationStructureNVX dst,
VkAccelerationStructureNVX src,
VkCopyAccelerationStructureModeNVX mode);
VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysNVX(
- VkCommandBuffer cmdBuf,
+ VkCommandBuffer commandBuffer,
VkBuffer raygenShaderBindingTableBuffer,
VkDeviceSize raygenShaderBindingOffset,
VkBuffer missShaderBindingTableBuffer,
@@ -8137,7 +8193,7 @@
void* pData);
VKAPI_ATTR void VKAPI_CALL vkCmdWriteAccelerationStructurePropertiesNVX(
- VkCommandBuffer cmdBuf,
+ VkCommandBuffer commandBuffer,
VkAccelerationStructureNVX accelerationStructure,
VkQueryType queryType,
VkQueryPool queryPool,
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index b32977a..009b257 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -78,7 +78,7 @@
native_bridge_(false),
refcount_(0) {}
- LayerLibrary(LayerLibrary&& other)
+ LayerLibrary(LayerLibrary&& other) noexcept
: path_(std::move(other.path_)),
filename_(std::move(other.filename_)),
dlhandle_(other.dlhandle_),
@@ -545,7 +545,7 @@
}
}
-LayerRef::LayerRef(LayerRef&& other) : layer_(other.layer_) {
+LayerRef::LayerRef(LayerRef&& other) noexcept : layer_(other.layer_) {
other.layer_ = nullptr;
}
diff --git a/vulkan/libvulkan/layers_extensions.h b/vulkan/libvulkan/layers_extensions.h
index 07ac1a3..1dae456 100644
--- a/vulkan/libvulkan/layers_extensions.h
+++ b/vulkan/libvulkan/layers_extensions.h
@@ -27,7 +27,7 @@
class LayerRef {
public:
explicit LayerRef(const Layer* layer);
- LayerRef(LayerRef&& other);
+ LayerRef(LayerRef&& other) noexcept;
~LayerRef();
LayerRef(const LayerRef&) = delete;
LayerRef& operator=(const LayerRef&) = delete;
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 6200383..f841862 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -544,6 +544,31 @@
template <typename Visitor>
inline bool Iterate(Visitor* visitor,
+ VkJsonExtDriverProperties* properties) {
+ return visitor->Visit("driverPropertiesKHR",
+ &properties->driver_properties_khr);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+ VkPhysicalDeviceDriverPropertiesKHR* properties) {
+ return visitor->Visit("driverID", &properties->driverID) &&
+ visitor->Visit("driverName", &properties->driverName) &&
+ visitor->Visit("driverInfo", &properties->driverInfo) &&
+ visitor->Visit("conformanceVersion", &properties->conformanceVersion);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
+ VkConformanceVersionKHR* version) {
+ return visitor->Visit("major", &version->major) &&
+ visitor->Visit("minor", &version->minor) &&
+ visitor->Visit("subminor", &version->subminor) &&
+ visitor->Visit("patch", &version->patch);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
VkJsonExtVariablePointerFeatures* features) {
return visitor->Visit("variablePointerFeaturesKHR",
&features->variable_pointer_features_khr);
@@ -769,13 +794,19 @@
case VK_API_VERSION_1_0:
ret &= visitor->Visit("properties", &device->properties) &&
visitor->Visit("features", &device->features) &&
- visitor->Visit("VK_KHR_variable_pointers",
- &device->ext_variable_pointer_features) &&
visitor->Visit("memory", &device->memory) &&
visitor->Visit("queues", &device->queues) &&
visitor->Visit("extensions", &device->extensions) &&
visitor->Visit("layers", &device->layers) &&
visitor->Visit("formats", &device->formats);
+ if (device->ext_driver_properties.reported) {
+ ret &= visitor->Visit("VK_KHR_driver_properties",
+ &device->ext_driver_properties);
+ }
+ if (device->ext_variable_pointer_features.reported) {
+ ret &= visitor->Visit("VK_KHR_variable_pointers",
+ &device->ext_variable_pointer_features);
+ }
}
return ret;
}
diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h
index 5e8428a..3373f19 100644
--- a/vulkan/vkjson/vkjson.h
+++ b/vulkan/vkjson/vkjson.h
@@ -46,11 +46,23 @@
std::vector<VkExtensionProperties> extensions;
};
+struct VkJsonExtDriverProperties {
+ VkJsonExtDriverProperties() {
+ reported = false;
+ memset(&driver_properties_khr, 0,
+ sizeof(VkPhysicalDeviceDriverPropertiesKHR));
+ }
+ bool reported;
+ VkPhysicalDeviceDriverPropertiesKHR driver_properties_khr;
+};
+
struct VkJsonExtVariablePointerFeatures {
VkJsonExtVariablePointerFeatures() {
+ reported = false;
memset(&variable_pointer_features_khr, 0,
sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR));
}
+ bool reported;
VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features_khr;
};
@@ -81,6 +93,7 @@
}
VkPhysicalDeviceProperties properties;
VkPhysicalDeviceFeatures features;
+ VkJsonExtDriverProperties ext_driver_properties;
VkJsonExtVariablePointerFeatures ext_variable_pointer_features;
VkPhysicalDeviceMemoryProperties memory;
std::vector<VkQueueFamilyProperties> queues;
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index db0450d..313d095 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -71,11 +71,16 @@
const char* const* instance_extensions) {
VkJsonDevice device;
+ PFN_vkGetPhysicalDeviceProperties2KHR vkpGetPhysicalDeviceProperties2KHR =
+ nullptr;
PFN_vkGetPhysicalDeviceFeatures2KHR vkpGetPhysicalDeviceFeatures2KHR =
nullptr;
if (instance != VK_NULL_HANDLE &&
HasExtension("VK_KHR_get_physical_device_properties2",
instance_extension_count, instance_extensions)) {
+ vkpGetPhysicalDeviceProperties2KHR =
+ reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2KHR>(
+ vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2KHR"));
vkpGetPhysicalDeviceFeatures2KHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
@@ -98,15 +103,32 @@
device.layers.data());
}
- vkGetPhysicalDeviceProperties(physical_device, &device.properties);
if (HasExtension("VK_KHR_get_physical_device_properties2",
instance_extension_count, instance_extensions)) {
+ VkPhysicalDeviceProperties2KHR properties = {
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
+ nullptr,
+ {} // properties
+ };
+ if (HasExtension("VK_KHR_driver_properties", device.extensions)) {
+ device.ext_driver_properties.reported = true;
+ device.ext_driver_properties.driver_properties_khr.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
+ device.ext_driver_properties.driver_properties_khr.pNext =
+ properties.pNext;
+ properties.pNext =
+ &device.ext_driver_properties.driver_properties_khr;
+ }
+ vkpGetPhysicalDeviceProperties2KHR(physical_device, &properties);
+ device.properties = properties.properties;
+
VkPhysicalDeviceFeatures2KHR features = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,
nullptr,
{} // features
};
if (HasExtension("VK_KHR_variable_pointers", device.extensions)) {
+ device.ext_variable_pointer_features.reported = true;
device.ext_variable_pointer_features.variable_pointer_features_khr.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
device.ext_variable_pointer_features.variable_pointer_features_khr.pNext =
@@ -117,6 +139,7 @@
vkpGetPhysicalDeviceFeatures2KHR(physical_device, &features);
device.features = features.features;
} else {
+ vkGetPhysicalDeviceProperties(physical_device, &device.properties);
vkGetPhysicalDeviceFeatures(physical_device, &device.features);
}
vkGetPhysicalDeviceMemoryProperties(physical_device, &device.memory);