Merge "Add alpha channel for the EGLConfig" into oc-dev
diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h
index 1f4387d..a680bc6 100644
--- a/include/gui/ISurfaceComposerClient.h
+++ b/include/gui/ISurfaceComposerClient.h
@@ -14,55 +14,52 @@
* limitations under the License.
*/
-#ifndef ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H
-#define ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
+#pragma once
#include <binder/IInterface.h>
-
-#include <ui/FrameStats.h>
+#include <binder/SafeInterface.h>
#include <ui/PixelFormat.h>
namespace android {
-// ----------------------------------------------------------------------------
+class FrameStats;
class IGraphicBufferProducer;
-class ISurfaceComposerClient : public IInterface
-{
+class ISurfaceComposerClient : public IInterface {
public:
DECLARE_META_INTERFACE(SurfaceComposerClient)
+ enum class Tag : uint32_t {
+ CreateSurface = IBinder::FIRST_CALL_TRANSACTION,
+ DestroySurface,
+ ClearLayerFrameStats,
+ GetLayerFrameStats,
+ Last,
+ };
+
// flags for createSurface()
enum { // (keep in sync with Surface.java)
- eHidden = 0x00000004,
- eDestroyBackbuffer = 0x00000020,
- eSecure = 0x00000080,
- eNonPremultiplied = 0x00000100,
- eOpaque = 0x00000400,
- eProtectedByApp = 0x00000800,
- eProtectedByDRM = 0x00001000,
- eCursorWindow = 0x00002000,
+ eHidden = 0x00000004,
+ eDestroyBackbuffer = 0x00000020,
+ eSecure = 0x00000080,
+ eNonPremultiplied = 0x00000100,
+ eOpaque = 0x00000400,
+ eProtectedByApp = 0x00000800,
+ eProtectedByDRM = 0x00001000,
+ eCursorWindow = 0x00002000,
- eFXSurfaceNormal = 0x00000000,
- eFXSurfaceDim = 0x00020000,
- eFXSurfaceMask = 0x000F0000,
+ eFXSurfaceNormal = 0x00000000,
+ eFXSurfaceDim = 0x00020000,
+ eFXSurfaceMask = 0x000F0000,
};
/*
* Requires ACCESS_SURFACE_FLINGER permission
*/
- virtual status_t createSurface(
- const String8& name, uint32_t w, uint32_t h,
- PixelFormat format, uint32_t flags,
- const sp<IBinder>& parent, uint32_t windowType, uint32_t ownerUid,
- sp<IBinder>* handle,
- sp<IGraphicBufferProducer>* gbp) = 0;
+ virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
+ uint32_t ownerUid, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp) = 0;
/*
* Requires ACCESS_SURFACE_FLINGER permission
@@ -78,21 +75,14 @@
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0;
-
- virtual status_t getTransformToDisplayInverse(const sp<IBinder>& handle,
- bool* outTransformToDisplayInverse) const = 0;
};
-// ----------------------------------------------------------------------------
-
-class BnSurfaceComposerClient: public BnInterface<ISurfaceComposerClient> {
+class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> {
public:
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags = 0);
+ BnSurfaceComposerClient()
+ : SafeBnInterface<ISurfaceComposerClient>("BnSurfaceComposerClient") {}
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
};
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_ISURFACE_COMPOSER_CLIENT_H
+} // namespace android
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 1e8cf76..394425a 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -169,9 +169,6 @@
status_t clearLayerFrameStats(const sp<IBinder>& token) const;
status_t getLayerFrameStats(const sp<IBinder>& token, FrameStats* outStats) const;
- status_t getTransformToDisplayInverse(const sp<IBinder>& token,
- bool* outTransformToDisplayInverse) const;
-
static status_t clearAnimationFrameStats();
static status_t getAnimationFrameStats(FrameStats* outStats);
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 8ee35bc..3cff7df 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -119,8 +119,6 @@
status_t clearLayerFrameStats() const;
status_t getLayerFrameStats(FrameStats* outStats) const;
- status_t getTransformToDisplayInverse(bool* outTransformToDisplayInverse) const;
-
private:
// can't be copied
SurfaceControl& operator = (SurfaceControl& rhs);
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 93b8684..b225128 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -71,6 +71,10 @@
"libutils",
],
+ export_include_dirs: [
+ "include",
+ ],
+
clang: true,
sanitize: {
misc_undefined: ["integer"],
diff --git a/libs/binder/include/binder/SafeInterface.h b/libs/binder/include/binder/SafeInterface.h
new file mode 100644
index 0000000..0e723c5
--- /dev/null
+++ b/libs/binder/include/binder/SafeInterface.h
@@ -0,0 +1,621 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <cutils/compiler.h>
+
+// Set to 1 to enable CallStacks when logging errors
+#define SI_DUMP_CALLSTACKS 0
+#if SI_DUMP_CALLSTACKS
+#include <utils/CallStack.h>
+#endif
+
+#include <functional>
+#include <type_traits>
+
+namespace android {
+namespace SafeInterface {
+
+// ParcelHandler is responsible for writing/reading various types to/from a Parcel in a generic way
+class ParcelHandler {
+public:
+ explicit ParcelHandler(const char* logTag) : mLogTag(logTag) {}
+
+ // Specializations for types with dedicated handling in Parcel
+ status_t read(const Parcel& parcel, bool* b) const {
+ return callParcel("readBool", [&]() { return parcel.readBool(b); });
+ }
+ status_t write(Parcel* parcel, bool b) const {
+ return callParcel("writeBool", [&]() { return parcel->writeBool(b); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type read(
+ const Parcel& parcel, T* t) const {
+ return callParcel("read(LightFlattenable)", [&]() { return parcel.read(*t); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_base_of<LightFlattenable<T>, T>::value, status_t>::type write(
+ Parcel* parcel, const T& t) const {
+ return callParcel("write(LightFlattenable)", [&]() { return parcel->write(t); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type read(
+ const Parcel& parcel, T* t) const {
+ return callParcel("readParcelable", [&]() { return parcel.readParcelable(t); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_base_of<Parcelable, T>::value, status_t>::type write(
+ Parcel* parcel, const T& t) const {
+ return callParcel("writeParcelable", [&]() { return parcel->writeParcelable(t); });
+ }
+ status_t read(const Parcel& parcel, String8* str) const {
+ return callParcel("readString8", [&]() { return parcel.readString8(str); });
+ }
+ status_t write(Parcel* parcel, const String8& str) const {
+ return callParcel("writeString8", [&]() { return parcel->writeString8(str); });
+ }
+ template <typename T>
+ status_t read(const Parcel& parcel, sp<T>* pointer) const {
+ return callParcel("readNullableStrongBinder",
+ [&]() { return parcel.readNullableStrongBinder(pointer); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_same<IBinder, T>::value, status_t>::type write(
+ Parcel* parcel, const sp<T>& pointer) const {
+ return callParcel("writeStrongBinder",
+ [&]() { return parcel->writeStrongBinder(pointer); });
+ }
+ template <typename T>
+ typename std::enable_if<std::is_base_of<IInterface, T>::value, status_t>::type write(
+ Parcel* parcel, const sp<T>& interface) const {
+ return write(parcel, IInterface::asBinder(interface));
+ }
+
+ // Templates to handle integral types. We use a struct template to require that the called
+ // function exactly matches the signedness and size of the argument (e.g., the argument isn't
+ // silently widened).
+ template <bool isSigned, size_t size, typename I>
+ struct HandleInt;
+ template <typename I>
+ struct HandleInt<true, 4, I> {
+ static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) {
+ return handler.callParcel("readInt32", [&]() { return parcel.readInt32(i); });
+ }
+ static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) {
+ return handler.callParcel("writeInt32", [&]() { return parcel->writeInt32(i); });
+ }
+ };
+ template <typename I>
+ struct HandleInt<false, 4, I> {
+ static status_t read(const ParcelHandler& handler, const Parcel& parcel, I* i) {
+ return handler.callParcel("readUint32", [&]() { return parcel.readUint32(i); });
+ }
+ static status_t write(const ParcelHandler& handler, Parcel* parcel, I i) {
+ return handler.callParcel("writeUint32", [&]() { return parcel->writeUint32(i); });
+ }
+ };
+ template <typename I>
+ typename std::enable_if<std::is_integral<I>::value, status_t>::type read(const Parcel& parcel,
+ I* i) const {
+ return HandleInt<std::is_signed<I>::value, sizeof(I), I>::read(*this, parcel, i);
+ }
+ template <typename I>
+ typename std::enable_if<std::is_integral<I>::value, status_t>::type write(Parcel* parcel,
+ I i) const {
+ return HandleInt<std::is_signed<I>::value, sizeof(I), I>::write(*this, parcel, i);
+ }
+
+private:
+ const char* const mLogTag;
+
+ // Helper to encapsulate error handling while calling the various Parcel methods
+ template <typename Function>
+ status_t callParcel(const char* name, Function f) const {
+ status_t error = f();
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ ALOG(LOG_ERROR, mLogTag, "Failed to %s, (%d: %s)", name, error, strerror(-error));
+#if SI_DUMP_CALLSTACKS
+ CallStack callStack(mLogTag);
+#endif
+ }
+ return error;
+ }
+};
+
+// Utility struct template which allows us to retrieve the types of the parameters of a member
+// function pointer
+template <typename T>
+struct ParamExtractor;
+template <typename Class, typename Return, typename... Params>
+struct ParamExtractor<Return (Class::*)(Params...)> {
+ using ParamTuple = std::tuple<Params...>;
+};
+template <typename Class, typename Return, typename... Params>
+struct ParamExtractor<Return (Class::*)(Params...) const> {
+ using ParamTuple = std::tuple<Params...>;
+};
+
+} // namespace SafeInterface
+
+template <typename Interface>
+class SafeBpInterface : public BpInterface<Interface> {
+protected:
+ SafeBpInterface(const sp<IBinder>& impl, const char* logTag)
+ : BpInterface<Interface>(impl), mLogTag(logTag) {}
+ ~SafeBpInterface() override = default;
+
+ // callRemote is used to invoke a synchronous procedure call over Binder
+ template <typename Method, typename TagType, typename... Args>
+ status_t callRemote(TagType tag, Args&&... args) const {
+ static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t");
+
+ // Verify that the arguments are compatible with the parameters
+ using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+ static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value,
+ "Invalid argument type");
+
+ // Write the input arguments to the data Parcel
+ Parcel data;
+ data.writeInterfaceToken(this->getInterfaceDescriptor());
+
+ status_t error = writeInputs(&data, std::forward<Args>(args)...);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by writeInputs
+ return error;
+ }
+
+ // Send the data Parcel to the remote and retrieve the reply parcel
+ Parcel reply;
+ error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error);
+#if SI_DUMP_CALLSTACKS
+ CallStack callStack(mLogTag);
+#endif
+ return error;
+ }
+
+ // Read the outputs from the reply Parcel into the output arguments
+ error = readOutputs(reply, std::forward<Args>(args)...);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by readOutputs
+ return error;
+ }
+
+ // Retrieve the result code from the reply Parcel
+ status_t result = NO_ERROR;
+ error = reply.readInt32(&result);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ ALOG(LOG_ERROR, mLogTag, "Failed to obtain result");
+#if SI_DUMP_CALLSTACKS
+ CallStack callStack(mLogTag);
+#endif
+ return error;
+ }
+ return result;
+ }
+
+ // callRemoteAsync is used to invoke an asynchronous procedure call over Binder
+ template <typename Method, typename TagType, typename... Args>
+ void callRemoteAsync(TagType tag, Args&&... args) const {
+ static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t");
+
+ // Verify that the arguments are compatible with the parameters
+ using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+ static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value,
+ "Invalid argument type");
+
+ // Write the input arguments to the data Parcel
+ Parcel data;
+ data.writeInterfaceToken(this->getInterfaceDescriptor());
+ status_t error = writeInputs(&data, std::forward<Args>(args)...);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by writeInputs
+ return;
+ }
+
+ // There will be no data in the reply Parcel since the call is one-way
+ Parcel reply;
+ error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply,
+ IBinder::FLAG_ONEWAY);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ ALOG(LOG_ERROR, mLogTag, "Failed to transact (%d)", error);
+#if SI_DUMP_CALLSTACKS
+ CallStack callStack(mLogTag);
+#endif
+ }
+ }
+
+private:
+ const char* const mLogTag;
+
+ // This struct provides information on whether the decayed types of the elements at Index in the
+ // tuple types T and U (that is, the types after stripping cv-qualifiers, removing references,
+ // and a few other less common operations) are the same
+ template <size_t Index, typename T, typename U>
+ struct DecayedElementsMatch {
+ private:
+ using FirstT = typename std::tuple_element<Index, T>::type;
+ using DecayedT = typename std::decay<FirstT>::type;
+ using FirstU = typename std::tuple_element<Index, U>::type;
+ using DecayedU = typename std::decay<FirstU>::type;
+
+ public:
+ static constexpr bool value = std::is_same<DecayedT, DecayedU>::value;
+ };
+
+ // When comparing whether the argument types match the parameter types, we first decay them (see
+ // DecayedElementsMatch) to avoid falsely flagging, say, T&& against T even though they are
+ // equivalent enough for our purposes
+ template <typename T, typename U>
+ struct ArgsMatchParams {};
+ template <typename... Args, typename... Params>
+ struct ArgsMatchParams<std::tuple<Args...>, std::tuple<Params...>> {
+ static_assert(sizeof...(Args) <= sizeof...(Params), "Too many arguments");
+ static_assert(sizeof...(Args) >= sizeof...(Params), "Not enough arguments");
+
+ private:
+ template <size_t Index>
+ static constexpr typename std::enable_if<(Index < sizeof...(Args)), bool>::type
+ elementsMatch() {
+ if (!DecayedElementsMatch<Index, std::tuple<Args...>, std::tuple<Params...>>::value) {
+ return false;
+ }
+ return elementsMatch<Index + 1>();
+ }
+ template <size_t Index>
+ static constexpr typename std::enable_if<(Index >= sizeof...(Args)), bool>::type
+ elementsMatch() {
+ return true;
+ }
+
+ public:
+ static constexpr bool value = elementsMatch<0>();
+ };
+
+ // Since we assume that pointer arguments are outputs, we can use this template struct to
+ // determine whether or not a given argument is fundamentally a pointer type and thus an output
+ template <typename T>
+ struct IsPointerIfDecayed {
+ private:
+ using Decayed = typename std::decay<T>::type;
+
+ public:
+ static constexpr bool value = std::is_pointer<Decayed>::value;
+ };
+
+ template <typename T>
+ typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type writeIfInput(
+ Parcel* data, T&& t) const {
+ return SafeInterface::ParcelHandler{mLogTag}.write(data, std::forward<T>(t));
+ }
+ template <typename T>
+ typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type writeIfInput(
+ Parcel* /*data*/, T&& /*t*/) const {
+ return NO_ERROR;
+ }
+
+ // This method iterates through all of the arguments, writing them to the data Parcel if they
+ // are an input (i.e., if they are not a pointer type)
+ template <typename T, typename... Remaining>
+ status_t writeInputs(Parcel* data, T&& t, Remaining&&... remaining) const {
+ status_t error = writeIfInput(data, std::forward<T>(t));
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by writeIfInput
+ return error;
+ }
+ return writeInputs(data, std::forward<Remaining>(remaining)...);
+ }
+ static status_t writeInputs(Parcel* /*data*/) { return NO_ERROR; }
+
+ template <typename T>
+ typename std::enable_if<IsPointerIfDecayed<T>::value, status_t>::type readIfOutput(
+ const Parcel& reply, T&& t) const {
+ return SafeInterface::ParcelHandler{mLogTag}.read(reply, std::forward<T>(t));
+ }
+ template <typename T>
+ static typename std::enable_if<!IsPointerIfDecayed<T>::value, status_t>::type readIfOutput(
+ const Parcel& /*reply*/, T&& /*t*/) {
+ return NO_ERROR;
+ }
+
+ // Similar to writeInputs except that it reads output arguments from the reply Parcel
+ template <typename T, typename... Remaining>
+ status_t readOutputs(const Parcel& reply, T&& t, Remaining&&... remaining) const {
+ status_t error = readIfOutput(reply, std::forward<T>(t));
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by readIfOutput
+ return error;
+ }
+ return readOutputs(reply, std::forward<Remaining>(remaining)...);
+ }
+ static status_t readOutputs(const Parcel& /*data*/) { return NO_ERROR; }
+};
+
+template <typename Interface>
+class SafeBnInterface : public BnInterface<Interface> {
+public:
+ explicit SafeBnInterface(const char* logTag) : mLogTag(logTag) {}
+
+protected:
+ template <typename Method>
+ status_t callLocal(const Parcel& data, Parcel* reply, Method method) {
+ CHECK_INTERFACE(this, data, reply);
+
+ // Since we need to both pass inputs into the call as well as retrieve outputs, we create a
+ // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the
+ // outputs. When we ultimately call into the method, we will pass the addresses of the
+ // output arguments instead of their tuple members directly, but the storage will live in
+ // the tuple.
+ using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+ typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{};
+
+ // Read the inputs from the data Parcel into the argument tuple
+ status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by read
+ return error;
+ }
+
+ // Call the local method
+ status_t result = MethodCaller<ParamTuple>::call(this, method, &rawArgs);
+
+ // Extract the outputs from the argument tuple and write them into the reply Parcel
+ error = OutputWriter<ParamTuple>{mLogTag}.writeOutputs(reply, &rawArgs);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by write
+ return error;
+ }
+
+ // Return the result code in the reply Parcel
+ error = reply->writeInt32(result);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ ALOG(LOG_ERROR, mLogTag, "Failed to write result");
+#if SI_DUMP_CALLSTACKS
+ CallStack callStack(mLogTag);
+#endif
+ return error;
+ }
+ return NO_ERROR;
+ }
+
+ template <typename Method>
+ status_t callLocalAsync(const Parcel& data, Parcel* /*reply*/, Method method) {
+ // reply is not actually used by CHECK_INTERFACE
+ CHECK_INTERFACE(this, data, reply);
+
+ // Since we need to both pass inputs into the call as well as retrieve outputs, we create a
+ // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the
+ // outputs. When we ultimately call into the method, we will pass the addresses of the
+ // output arguments instead of their tuple members directly, but the storage will live in
+ // the tuple.
+ using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
+ typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{};
+
+ // Read the inputs from the data Parcel into the argument tuple
+ status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged by read
+ return error;
+ }
+
+ // Call the local method
+ MethodCaller<ParamTuple>::callVoid(this, method, &rawArgs);
+
+ // After calling, there is nothing more to do since asynchronous calls do not return a value
+ // to the caller
+ return NO_ERROR;
+ }
+
+private:
+ const char* const mLogTag;
+
+ // RemoveFirst strips the first element from a tuple.
+ // For example, given T = std::tuple<A, B, C>, RemoveFirst<T>::type = std::tuple<B, C>
+ template <typename T, typename... Args>
+ struct RemoveFirst;
+ template <typename T, typename... Args>
+ struct RemoveFirst<std::tuple<T, Args...>> {
+ using type = std::tuple<Args...>;
+ };
+
+ // RawConverter strips a tuple down to its fundamental types, discarding both pointers and
+ // references. This allows us to allocate storage for both input (non-pointer) arguments and
+ // output (pointer) arguments in one tuple.
+ // For example, given T = std::tuple<const A&, B*>, RawConverter<T>::type = std::tuple<A, B>
+ template <typename Unconverted, typename... Converted>
+ struct RawConverter;
+ template <typename Unconverted, typename... Converted>
+ struct RawConverter<std::tuple<Converted...>, Unconverted> {
+ private:
+ using ElementType = typename std::tuple_element<0, Unconverted>::type;
+ using Decayed = typename std::decay<ElementType>::type;
+ using WithoutPointer = typename std::remove_pointer<Decayed>::type;
+
+ public:
+ using type = typename RawConverter<std::tuple<Converted..., WithoutPointer>,
+ typename RemoveFirst<Unconverted>::type>::type;
+ };
+ template <typename... Converted>
+ struct RawConverter<std::tuple<Converted...>, std::tuple<>> {
+ using type = std::tuple<Converted...>;
+ };
+
+ // This provides a simple way to determine whether the indexed element of Args... is a pointer
+ template <size_t I, typename... Args>
+ struct ElementIsPointer {
+ private:
+ using ElementType = typename std::tuple_element<I, std::tuple<Args...>>::type;
+
+ public:
+ static constexpr bool value = std::is_pointer<ElementType>::value;
+ };
+
+ // This class iterates over the parameter types, and if a given parameter is an input
+ // (i.e., is not a pointer), reads the corresponding argument tuple element from the data Parcel
+ template <typename... Params>
+ class InputReader;
+ template <typename... Params>
+ class InputReader<std::tuple<Params...>> {
+ public:
+ explicit InputReader(const char* logTag) : mLogTag(logTag) {}
+
+ // Note that in this case (as opposed to in SafeBpInterface), we iterate using an explicit
+ // index (starting with 0 here) instead of using recursion and stripping the first element.
+ // This is because in SafeBpInterface we aren't actually operating on a real tuple, but are
+ // instead just using a tuple as a convenient container for variadic types, whereas here we
+ // can't modify the argument tuple without causing unnecessary copies or moves of the data
+ // contained therein.
+ template <typename RawTuple>
+ status_t readInputs(const Parcel& data, RawTuple* args) {
+ return dispatchArg<0>(data, args);
+ }
+
+ private:
+ const char* const mLogTag;
+
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<!ElementIsPointer<I, Params...>::value, status_t>::type readIfInput(
+ const Parcel& data, RawTuple* args) {
+ return SafeInterface::ParcelHandler{mLogTag}.read(data, &std::get<I>(*args));
+ }
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<ElementIsPointer<I, Params...>::value, status_t>::type readIfInput(
+ const Parcel& /*data*/, RawTuple* /*args*/) {
+ return NO_ERROR;
+ }
+
+ // Recursively iterate through the arguments
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg(
+ const Parcel& data, RawTuple* args) {
+ status_t error = readIfInput<I>(data, args);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged in read
+ return error;
+ }
+ return dispatchArg<I + 1>(data, args);
+ }
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<(I >= sizeof...(Params)), status_t>::type dispatchArg(
+ const Parcel& /*data*/, RawTuple* /*args*/) {
+ return NO_ERROR;
+ }
+ };
+
+ // getForCall uses the types of the parameters to determine whether a given element of the
+ // argument tuple is an input, which should be passed directly into the call, or an output, for
+ // which its address should be passed into the call
+ template <size_t I, typename RawTuple, typename... Params>
+ static typename std::enable_if<
+ ElementIsPointer<I, Params...>::value,
+ typename std::tuple_element<I, std::tuple<Params...>>::type>::type
+ getForCall(RawTuple* args) {
+ return &std::get<I>(*args);
+ }
+ template <size_t I, typename RawTuple, typename... Params>
+ static typename std::enable_if<
+ !ElementIsPointer<I, Params...>::value,
+ typename std::tuple_element<I, std::tuple<Params...>>::type>::type&
+ getForCall(RawTuple* args) {
+ return std::get<I>(*args);
+ }
+
+ // This template class uses std::index_sequence and parameter pack expansion to call the given
+ // method using the elements of the argument tuple (after those arguments are passed through
+ // getForCall to get addresses instead of values for output arguments)
+ template <typename... Params>
+ struct MethodCaller;
+ template <typename... Params>
+ struct MethodCaller<std::tuple<Params...>> {
+ public:
+ // The calls through these to the helper methods are necessary to generate the
+ // std::index_sequences used to unpack the argument tuple into the method call
+ template <typename Class, typename MemberFunction, typename RawTuple>
+ static status_t call(Class* instance, MemberFunction function, RawTuple* args) {
+ return callHelper(instance, function, args, std::index_sequence_for<Params...>{});
+ }
+ template <typename Class, typename MemberFunction, typename RawTuple>
+ static void callVoid(Class* instance, MemberFunction function, RawTuple* args) {
+ callVoidHelper(instance, function, args, std::index_sequence_for<Params...>{});
+ }
+
+ private:
+ template <typename Class, typename MemberFunction, typename RawTuple, std::size_t... I>
+ static status_t callHelper(Class* instance, MemberFunction function, RawTuple* args,
+ std::index_sequence<I...> /*unused*/) {
+ return (instance->*function)(getForCall<I, RawTuple, Params...>(args)...);
+ }
+ template <typename Class, typename MemberFunction, typename RawTuple, std::size_t... I>
+ static void callVoidHelper(Class* instance, MemberFunction function, RawTuple* args,
+ std::index_sequence<I...> /*unused*/) {
+ (instance->*function)(getForCall<I, RawTuple, Params...>(args)...);
+ }
+ };
+
+ // This class iterates over the parameter types, and if a given parameter is an output
+ // (i.e., is a pointer), writes the corresponding argument tuple element into the reply Parcel
+ template <typename... Params>
+ struct OutputWriter;
+ template <typename... Params>
+ struct OutputWriter<std::tuple<Params...>> {
+ public:
+ explicit OutputWriter(const char* logTag) : mLogTag(logTag) {}
+
+ // See the note on InputReader::readInputs for why this differs from the arguably simpler
+ // RemoveFirst approach in SafeBpInterface
+ template <typename RawTuple>
+ status_t writeOutputs(Parcel* reply, RawTuple* args) {
+ return dispatchArg<0>(reply, args);
+ }
+
+ private:
+ const char* const mLogTag;
+
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<ElementIsPointer<I, Params...>::value, status_t>::type
+ writeIfOutput(Parcel* reply, RawTuple* args) {
+ return SafeInterface::ParcelHandler{mLogTag}.write(reply, std::get<I>(*args));
+ }
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<!ElementIsPointer<I, Params...>::value, status_t>::type
+ writeIfOutput(Parcel* /*reply*/, RawTuple* /*args*/) {
+ return NO_ERROR;
+ }
+
+ // Recursively iterate through the arguments
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg(
+ Parcel* reply, RawTuple* args) {
+ status_t error = writeIfOutput<I>(reply, args);
+ if (CC_UNLIKELY(error != NO_ERROR)) {
+ // A message will have been logged in read
+ return error;
+ }
+ return dispatchArg<I + 1>(reply, args);
+ }
+ template <std::size_t I, typename RawTuple>
+ typename std::enable_if<(I >= sizeof...(Params)), status_t>::type dispatchArg(
+ Parcel* /*reply*/, RawTuple* /*args*/) {
+ return NO_ERROR;
+ }
+ };
+};
+
+} // namespace android
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 327ecad..1ee4b6f 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -80,3 +80,27 @@
"libbase",
],
}
+
+cc_test {
+ name: "binderSafeInterfaceTest",
+ srcs: ["binderSafeInterfaceTest.cpp"],
+
+ cppflags: [
+ "-Werror",
+ "-Weverything",
+ "-Wno-c++98-compat",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-global-constructors",
+ "-Wno-padded",
+ "-Wno-weak-vtables",
+ ],
+
+ cpp_std: "experimental",
+ gnu_extensions: false,
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+}
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
new file mode 100644
index 0000000..ac2f4d5
--- /dev/null
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/SafeInterface.h>
+
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/ProcessState.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Weverything"
+#include <gtest/gtest.h>
+#pragma clang diagnostic pop
+
+#include <optional>
+
+using namespace std::chrono_literals; // NOLINT - google-build-using-namespace
+
+namespace android {
+namespace tests {
+
+// This class serves two purposes:
+// 1) It ensures that the implementation doesn't require copying or moving the data (for
+// efficiency purposes)
+// 2) It tests that Parcelables can be passed correctly
+class NoCopyNoMove : public Parcelable {
+public:
+ NoCopyNoMove() = default;
+ explicit NoCopyNoMove(int32_t value) : mValue(value) {}
+ ~NoCopyNoMove() override = default;
+
+ // Not copyable
+ NoCopyNoMove(const NoCopyNoMove&) = delete;
+ NoCopyNoMove& operator=(const NoCopyNoMove&) = delete;
+
+ // Not movable
+ NoCopyNoMove(NoCopyNoMove&&) = delete;
+ NoCopyNoMove& operator=(NoCopyNoMove&&) = delete;
+
+ // Parcelable interface
+ status_t writeToParcel(Parcel* parcel) const override { return parcel->writeInt32(mValue); }
+ status_t readFromParcel(const Parcel* parcel) override { return parcel->readInt32(&mValue); }
+
+ int32_t getValue() const { return mValue; }
+ void setValue(int32_t value) { mValue = value; }
+
+private:
+ int32_t mValue = 0;
+ uint8_t mPadding[4] = {}; // Avoids a warning from -Wpadded
+};
+
+struct TestLightFlattenable : LightFlattenablePod<TestLightFlattenable> {
+ TestLightFlattenable() = default;
+ explicit TestLightFlattenable(int32_t v) : value(v) {}
+ int32_t value = 0;
+};
+
+class ExitOnDeath : public IBinder::DeathRecipient {
+public:
+ ~ExitOnDeath() override = default;
+
+ void binderDied(const wp<IBinder>& /*who*/) override {
+ ALOG(LOG_INFO, "ExitOnDeath", "Exiting");
+ exit(0);
+ }
+};
+
+// This callback class is used to test both one-way transactions and that sp<IInterface> can be
+// passed correctly
+class ICallback : public IInterface {
+public:
+ DECLARE_META_INTERFACE(Callback)
+
+ enum class Tag : uint32_t {
+ OnCallback = IBinder::FIRST_CALL_TRANSACTION,
+ Last,
+ };
+
+ virtual void onCallback(int32_t aPlusOne) = 0;
+};
+
+class BpCallback : public SafeBpInterface<ICallback> {
+public:
+ explicit BpCallback(const sp<IBinder>& impl) : SafeBpInterface<ICallback>(impl, getLogTag()) {}
+
+ void onCallback(int32_t aPlusOne) override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemoteAsync<decltype(&ICallback::onCallback)>(Tag::OnCallback, aPlusOne);
+ }
+
+private:
+ static constexpr const char* getLogTag() { return "BpCallback"; }
+};
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+IMPLEMENT_META_INTERFACE(Callback, "android.gfx.tests.ICallback");
+#pragma clang diagnostic pop
+
+class BnCallback : public SafeBnInterface<ICallback> {
+public:
+ BnCallback() : SafeBnInterface("BnCallback") {}
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t /*flags*/) override {
+ EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
+ EXPECT_LT(code, static_cast<uint32_t>(ICallback::Tag::Last));
+ ICallback::Tag tag = static_cast<ICallback::Tag>(code);
+ switch (tag) {
+ case ICallback::Tag::OnCallback: {
+ return callLocalAsync(data, reply, &ICallback::onCallback);
+ }
+ case ICallback::Tag::Last:
+ // Should not be possible because of the asserts at the beginning of the method
+ [&]() { FAIL(); }();
+ return UNKNOWN_ERROR;
+ }
+ }
+};
+
+class ISafeInterfaceTest : public IInterface {
+public:
+ DECLARE_META_INTERFACE(SafeInterfaceTest)
+
+ enum class Tag : uint32_t {
+ SetDeathToken = IBinder::FIRST_CALL_TRANSACTION,
+ ReturnsNoMemory,
+ LogicalNot,
+ IncrementLightFlattenable,
+ IncrementNoCopyNoMove,
+ ToUpper,
+ CallMeBack,
+ IncrementInt32,
+ IncrementUint32,
+ IncrementTwo,
+ Last,
+ };
+
+ // This is primarily so that the remote service dies when the test does, but it also serves to
+ // test the handling of sp<IBinder> and non-const methods
+ virtual status_t setDeathToken(const sp<IBinder>& token) = 0;
+
+ // This is the most basic test since it doesn't require parceling any arguments
+ virtual status_t returnsNoMemory() const = 0;
+
+ // These are ordered according to their corresponding methods in SafeInterface::ParcelHandler
+ virtual status_t logicalNot(bool a, bool* notA) const = 0;
+ virtual status_t increment(const TestLightFlattenable& a,
+ TestLightFlattenable* aPlusOne) const = 0;
+ virtual status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const = 0;
+ virtual status_t toUpper(const String8& str, String8* upperStr) const = 0;
+ // As mentioned above, sp<IBinder> is already tested by setDeathToken
+ virtual void callMeBack(const sp<ICallback>& callback, int32_t a) const = 0;
+ virtual status_t increment(int32_t a, int32_t* aPlusOne) const = 0;
+ virtual status_t increment(uint32_t a, uint32_t* aPlusOne) const = 0;
+
+ // This tests that input/output parameter interleaving works correctly
+ virtual status_t increment(int32_t a, int32_t* aPlusOne, int32_t b,
+ int32_t* bPlusOne) const = 0;
+};
+
+class BpSafeInterfaceTest : public SafeBpInterface<ISafeInterfaceTest> {
+public:
+ explicit BpSafeInterfaceTest(const sp<IBinder>& impl)
+ : SafeBpInterface<ISafeInterfaceTest>(impl, getLogTag()) {}
+
+ status_t setDeathToken(const sp<IBinder>& token) override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemote<decltype(&ISafeInterfaceTest::setDeathToken)>(Tag::SetDeathToken, token);
+ }
+ status_t returnsNoMemory() const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemote<decltype(&ISafeInterfaceTest::returnsNoMemory)>(Tag::ReturnsNoMemory);
+ }
+ status_t logicalNot(bool a, bool* notA) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemote<decltype(&ISafeInterfaceTest::logicalNot)>(Tag::LogicalNot, a, notA);
+ }
+ status_t increment(const TestLightFlattenable& a,
+ TestLightFlattenable* aPlusOne) const override {
+ using Signature = status_t (ISafeInterfaceTest::*)(const TestLightFlattenable&,
+ TestLightFlattenable*) const;
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemote<Signature>(Tag::IncrementLightFlattenable, a, aPlusOne);
+ }
+ status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
+ NoCopyNoMove* aPlusOne) const;
+ return callRemote<Signature>(Tag::IncrementNoCopyNoMove, a, aPlusOne);
+ }
+ status_t toUpper(const String8& str, String8* upperStr) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemote<decltype(&ISafeInterfaceTest::toUpper)>(Tag::ToUpper, str, upperStr);
+ }
+ void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return callRemoteAsync<decltype(&ISafeInterfaceTest::callMeBack)>(Tag::CallMeBack, callback,
+ a);
+ }
+ status_t increment(int32_t a, int32_t* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*) const;
+ return callRemote<Signature>(Tag::IncrementInt32, a, aPlusOne);
+ }
+ status_t increment(uint32_t a, uint32_t* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const;
+ return callRemote<Signature>(Tag::IncrementUint32, a, aPlusOne);
+ }
+ status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ using Signature =
+ status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t, int32_t*) const;
+ return callRemote<Signature>(Tag::IncrementTwo, a, aPlusOne, b, bPlusOne);
+ }
+
+private:
+ static constexpr const char* getLogTag() { return "BpSafeInterfaceTest"; }
+};
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+IMPLEMENT_META_INTERFACE(SafeInterfaceTest, "android.gfx.tests.ISafeInterfaceTest");
+
+static sp<IBinder::DeathRecipient> getDeathRecipient() {
+ static sp<IBinder::DeathRecipient> recipient = new ExitOnDeath;
+ return recipient;
+}
+#pragma clang diagnostic pop
+
+class BnSafeInterfaceTest : public SafeBnInterface<ISafeInterfaceTest> {
+public:
+ BnSafeInterfaceTest() : SafeBnInterface(getLogTag()) {}
+
+ status_t setDeathToken(const sp<IBinder>& token) override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ token->linkToDeath(getDeathRecipient());
+ return NO_ERROR;
+ }
+ status_t returnsNoMemory() const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ return NO_MEMORY;
+ }
+ status_t logicalNot(bool a, bool* notA) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *notA = !a;
+ return NO_ERROR;
+ }
+ status_t increment(const TestLightFlattenable& a,
+ TestLightFlattenable* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ aPlusOne->value = a.value + 1;
+ return NO_ERROR;
+ }
+ status_t increment(const NoCopyNoMove& a, NoCopyNoMove* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ aPlusOne->setValue(a.getValue() + 1);
+ return NO_ERROR;
+ }
+ status_t toUpper(const String8& str, String8* upperStr) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *upperStr = str;
+ upperStr->toUpper();
+ return NO_ERROR;
+ }
+ void callMeBack(const sp<ICallback>& callback, int32_t a) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ callback->onCallback(a + 1);
+ }
+ status_t increment(int32_t a, int32_t* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *aPlusOne = a + 1;
+ return NO_ERROR;
+ }
+ status_t increment(uint32_t a, uint32_t* aPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *aPlusOne = a + 1;
+ return NO_ERROR;
+ }
+ status_t increment(int32_t a, int32_t* aPlusOne, int32_t b, int32_t* bPlusOne) const override {
+ ALOG(LOG_INFO, getLogTag(), "%s", __PRETTY_FUNCTION__);
+ *aPlusOne = a + 1;
+ *bPlusOne = b + 1;
+ return NO_ERROR;
+ }
+
+ // BnInterface
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t /*flags*/) override {
+ EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
+ EXPECT_LT(code, static_cast<uint32_t>(Tag::Last));
+ ISafeInterfaceTest::Tag tag = static_cast<ISafeInterfaceTest::Tag>(code);
+ switch (tag) {
+ case ISafeInterfaceTest::Tag::SetDeathToken: {
+ return callLocal(data, reply, &ISafeInterfaceTest::setDeathToken);
+ }
+ case ISafeInterfaceTest::Tag::ReturnsNoMemory: {
+ return callLocal(data, reply, &ISafeInterfaceTest::returnsNoMemory);
+ }
+ case ISafeInterfaceTest::Tag::LogicalNot: {
+ return callLocal(data, reply, &ISafeInterfaceTest::logicalNot);
+ }
+ case ISafeInterfaceTest::Tag::IncrementLightFlattenable: {
+ using Signature =
+ status_t (ISafeInterfaceTest::*)(const TestLightFlattenable& a,
+ TestLightFlattenable* aPlusOne) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
+ case ISafeInterfaceTest::Tag::IncrementNoCopyNoMove: {
+ using Signature = status_t (ISafeInterfaceTest::*)(const NoCopyNoMove& a,
+ NoCopyNoMove* aPlusOne) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
+ case ISafeInterfaceTest::Tag::ToUpper: {
+ return callLocal(data, reply, &ISafeInterfaceTest::toUpper);
+ }
+ case ISafeInterfaceTest::Tag::CallMeBack: {
+ return callLocalAsync(data, reply, &ISafeInterfaceTest::callMeBack);
+ }
+ case ISafeInterfaceTest::Tag::IncrementInt32: {
+ using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
+ case ISafeInterfaceTest::Tag::IncrementUint32: {
+ using Signature = status_t (ISafeInterfaceTest::*)(uint32_t, uint32_t*) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
+ case ISafeInterfaceTest::Tag::IncrementTwo: {
+ using Signature = status_t (ISafeInterfaceTest::*)(int32_t, int32_t*, int32_t,
+ int32_t*) const;
+ return callLocal<Signature>(data, reply, &ISafeInterfaceTest::increment);
+ }
+ case ISafeInterfaceTest::Tag::Last:
+ // Should not be possible because of the asserts at the beginning of the method
+ [&]() { FAIL(); }();
+ return UNKNOWN_ERROR;
+ }
+ }
+
+private:
+ static constexpr const char* getLogTag() { return "BnSafeInterfaceTest"; }
+};
+
+class SafeInterfaceTest : public ::testing::Test {
+public:
+ SafeInterfaceTest() : mSafeInterfaceTest(getRemoteService()) {
+ ProcessState::self()->startThreadPool();
+ }
+ ~SafeInterfaceTest() override = default;
+
+protected:
+ sp<ISafeInterfaceTest> mSafeInterfaceTest;
+
+private:
+ static constexpr const char* getLogTag() { return "SafeInterfaceTest"; }
+
+ sp<ISafeInterfaceTest> getRemoteService() {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wexit-time-destructors"
+ static std::mutex sMutex;
+ static sp<ISafeInterfaceTest> sService;
+ static sp<IBinder> sDeathToken = new BBinder;
+#pragma clang diagnostic pop
+
+ std::unique_lock<decltype(sMutex)> lock;
+ if (sService == nullptr) {
+ ALOG(LOG_INFO, getLogTag(), "Forking remote process");
+ pid_t forkPid = fork();
+ EXPECT_NE(forkPid, -1);
+
+ const String16 serviceName("SafeInterfaceTest");
+
+ if (forkPid == 0) {
+ ALOG(LOG_INFO, getLogTag(), "Remote process checking in");
+ sp<ISafeInterfaceTest> nativeService = new BnSafeInterfaceTest;
+ defaultServiceManager()->addService(serviceName,
+ IInterface::asBinder(nativeService));
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+ // We shouldn't get to this point
+ [&]() { FAIL(); }();
+ }
+
+ sp<IBinder> binder = defaultServiceManager()->getService(serviceName);
+ sService = interface_cast<ISafeInterfaceTest>(binder);
+ EXPECT_TRUE(sService != nullptr);
+
+ sService->setDeathToken(sDeathToken);
+ }
+
+ return sService;
+ }
+};
+
+TEST_F(SafeInterfaceTest, TestReturnsNoMemory) {
+ status_t result = mSafeInterfaceTest->returnsNoMemory();
+ ASSERT_EQ(NO_MEMORY, result);
+}
+
+TEST_F(SafeInterfaceTest, TestLogicalNot) {
+ const bool a = true;
+ bool notA = true;
+ status_t result = mSafeInterfaceTest->logicalNot(a, ¬A);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(!a, notA);
+ // Test both since we don't want to accidentally catch a default false somewhere
+ const bool b = false;
+ bool notB = false;
+ result = mSafeInterfaceTest->logicalNot(b, ¬B);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(!b, notB);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementLightFlattenable) {
+ const TestLightFlattenable a{1};
+ TestLightFlattenable aPlusOne{0};
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a.value + 1, aPlusOne.value);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementNoCopyNoMove) {
+ const NoCopyNoMove a{1};
+ NoCopyNoMove aPlusOne{0};
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a.getValue() + 1, aPlusOne.getValue());
+}
+
+TEST_F(SafeInterfaceTest, TestToUpper) {
+ const String8 str{"Hello, world!"};
+ String8 upperStr;
+ status_t result = mSafeInterfaceTest->toUpper(str, &upperStr);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_TRUE(upperStr == String8{"HELLO, WORLD!"});
+}
+
+TEST_F(SafeInterfaceTest, TestCallMeBack) {
+ class CallbackReceiver : public BnCallback {
+ public:
+ void onCallback(int32_t aPlusOne) override {
+ ALOG(LOG_INFO, "CallbackReceiver", "%s", __PRETTY_FUNCTION__);
+ std::unique_lock<decltype(mMutex)> lock(mMutex);
+ mValue = aPlusOne;
+ mCondition.notify_one();
+ }
+
+ std::optional<int32_t> waitForCallback() {
+ std::unique_lock<decltype(mMutex)> lock(mMutex);
+ bool success =
+ mCondition.wait_for(lock, 100ms, [&]() { return static_cast<bool>(mValue); });
+ return success ? mValue : std::nullopt;
+ }
+
+ private:
+ std::mutex mMutex;
+ std::condition_variable mCondition;
+ std::optional<int32_t> mValue;
+ };
+
+ sp<CallbackReceiver> receiver = new CallbackReceiver;
+ const int32_t a = 1;
+ mSafeInterfaceTest->callMeBack(receiver, a);
+ auto result = receiver->waitForCallback();
+ ASSERT_TRUE(result);
+ ASSERT_EQ(a + 1, *result);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementInt32) {
+ const int32_t a = 1;
+ int32_t aPlusOne = 0;
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a + 1, aPlusOne);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementUint32) {
+ const uint32_t a = 1;
+ uint32_t aPlusOne = 0;
+ status_t result = mSafeInterfaceTest->increment(a, &aPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a + 1, aPlusOne);
+}
+
+TEST_F(SafeInterfaceTest, TestIncrementTwo) {
+ const int32_t a = 1;
+ int32_t aPlusOne = 0;
+ const int32_t b = 2;
+ int32_t bPlusOne = 0;
+ status_t result = mSafeInterfaceTest->increment(1, &aPlusOne, 2, &bPlusOne);
+ ASSERT_EQ(NO_ERROR, result);
+ ASSERT_EQ(a + 1, aPlusOne);
+ ASSERT_EQ(b + 1, bPlusOne);
+}
+
+} // namespace tests
+} // namespace android
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index db8a517..2d2146b 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -17,116 +17,56 @@
// tag as surfaceflinger
#define LOG_TAG "SurfaceFlinger"
-#include <stdio.h>
#include <stdint.h>
+#include <stdio.h>
#include <sys/types.h>
-#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/SafeInterface.h>
+#include <ui/FrameStats.h>
#include <ui/Point.h>
#include <ui/Rect.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposerClient.h>
-#include <private/gui/LayerState.h>
-
-// ---------------------------------------------------------------------------
namespace android {
-enum {
- CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
- DESTROY_SURFACE,
- CLEAR_LAYER_FRAME_STATS,
- GET_LAYER_FRAME_STATS,
- GET_TRANSFORM_TO_DISPLAY_INVERSE
-};
-
-class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
-{
+class BpSurfaceComposerClient : public SafeBpInterface<ISurfaceComposerClient> {
public:
explicit BpSurfaceComposerClient(const sp<IBinder>& impl)
- : BpInterface<ISurfaceComposerClient>(impl) {
+ : SafeBpInterface<ISurfaceComposerClient>(impl, "BpSurfaceComposerClient") {}
+
+ ~BpSurfaceComposerClient() override;
+
+ status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,
+ uint32_t flags, const sp<IBinder>& parent, uint32_t windowType,
+ uint32_t ownerUid, sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp) override {
+ return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CreateSurface,
+ name, width, height,
+ format, flags, parent,
+ windowType, ownerUid,
+ handle, gbp);
}
- virtual ~BpSurfaceComposerClient();
-
- virtual status_t createSurface(const String8& name, uint32_t width,
- uint32_t height, PixelFormat format, uint32_t flags,
- const sp<IBinder>& parent, uint32_t windowType, uint32_t ownerUid,
- sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeString8(name);
- data.writeUint32(width);
- data.writeUint32(height);
- data.writeInt32(static_cast<int32_t>(format));
- data.writeUint32(flags);
- data.writeUint32(windowType);
- data.writeUint32(ownerUid);
- if (parent != nullptr) {
- data.writeStrongBinder(parent);
- }
- remote()->transact(CREATE_SURFACE, data, &reply);
- *handle = reply.readStrongBinder();
- *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
- return reply.readInt32();
+ status_t destroySurface(const sp<IBinder>& handle) override {
+ return callRemote<decltype(&ISurfaceComposerClient::destroySurface)>(Tag::DestroySurface,
+ handle);
}
- virtual status_t destroySurface(const sp<IBinder>& handle) {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeStrongBinder(handle);
- remote()->transact(DESTROY_SURFACE, data, &reply);
- return reply.readInt32();
+ status_t clearLayerFrameStats(const sp<IBinder>& handle) const override {
+ return callRemote<decltype(
+ &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::ClearLayerFrameStats, handle);
}
- virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeStrongBinder(handle);
- remote()->transact(CLEAR_LAYER_FRAME_STATS, data, &reply);
- return reply.readInt32();
- }
-
- virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeStrongBinder(handle);
- remote()->transact(GET_LAYER_FRAME_STATS, data, &reply);
- reply.read(*outStats);
- return reply.readInt32();
- }
-
- virtual status_t getTransformToDisplayInverse(const sp<IBinder>& handle,
- bool* outTransformToDisplayInverse) const {
- Parcel data, reply;
- status_t result =
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- if (result != NO_ERROR) {
- return result;
- }
- result = data.writeStrongBinder(handle);
- if (result != NO_ERROR) {
- return result;
- }
- result = remote()->transact(GET_TRANSFORM_TO_DISPLAY_INVERSE, data, &reply);
- if (result != NO_ERROR) {
- return result;
- }
- int transformInverse;
- result = reply.readInt32(&transformInverse);
- if (result != NO_ERROR) {
- return result;
- }
- *outTransformToDisplayInverse = transformInverse != 0 ? true : false;
- status_t result2 = reply.readInt32(&result);
- if (result2 != NO_ERROR) {
- return result2;
- }
- return result;
+ status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const override {
+ return callRemote<decltype(
+ &ISurfaceComposerClient::getLayerFrameStats)>(Tag::GetLayerFrameStats, handle,
+ outStats);
}
};
@@ -138,75 +78,29 @@
// ----------------------------------------------------------------------
-status_t BnSurfaceComposerClient::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case CREATE_SURFACE: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- String8 name = data.readString8();
- uint32_t width = data.readUint32();
- uint32_t height = data.readUint32();
- PixelFormat format = static_cast<PixelFormat>(data.readInt32());
- uint32_t createFlags = data.readUint32();
- uint32_t windowType = data.readUint32();
- uint32_t ownerUid = data.readUint32();
- sp<IBinder> parent = nullptr;
- if (data.dataAvail() > 0) {
- parent = data.readStrongBinder();
- }
- sp<IBinder> handle;
- sp<IGraphicBufferProducer> gbp;
- status_t result = createSurface(name, width, height, format,
- createFlags, parent, windowType, ownerUid, &handle, &gbp);
- reply->writeStrongBinder(handle);
- reply->writeStrongBinder(IInterface::asBinder(gbp));
- reply->writeInt32(result);
- return NO_ERROR;
+status_t BnSurfaceComposerClient::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags) {
+ if (code < IBinder::FIRST_CALL_TRANSACTION || code >= static_cast<uint32_t>(Tag::Last)) {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ auto tag = static_cast<Tag>(code);
+ switch (tag) {
+ case Tag::CreateSurface: {
+ return callLocal(data, reply, &ISurfaceComposerClient::createSurface);
}
- case DESTROY_SURFACE: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- reply->writeInt32(destroySurface( data.readStrongBinder() ) );
- return NO_ERROR;
+ case Tag::DestroySurface: {
+ return callLocal(data, reply, &ISurfaceComposerClient::destroySurface);
}
- case CLEAR_LAYER_FRAME_STATS: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- sp<IBinder> handle = data.readStrongBinder();
- status_t result = clearLayerFrameStats(handle);
- reply->writeInt32(result);
- return NO_ERROR;
+ case Tag::ClearLayerFrameStats: {
+ return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
}
- case GET_LAYER_FRAME_STATS: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- sp<IBinder> handle = data.readStrongBinder();
- FrameStats stats;
- status_t result = getLayerFrameStats(handle, &stats);
- reply->write(stats);
- reply->writeInt32(result);
- return NO_ERROR;
+ case Tag::GetLayerFrameStats: {
+ return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats);
}
- case GET_TRANSFORM_TO_DISPLAY_INVERSE: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- sp<IBinder> handle;
- status_t result = data.readStrongBinder(&handle);
- if (result != NO_ERROR) {
- return result;
- }
- bool transformInverse = false;
- result = getTransformToDisplayInverse(handle, &transformInverse);
- if (result != NO_ERROR) {
- return result;
- }
- result = reply->writeInt32(transformInverse ? 1 : 0);
- if (result != NO_ERROR) {
- return result;
- }
- result = reply->writeInt32(NO_ERROR);
- return result;
- }
- default:
+ case Tag::Last:
+ // Should not be possible because of the check at the beginning of the method
return BBinder::onTransact(code, data, reply, flags);
}
}
-}; // namespace android
+} // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 088933a..56c7586 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -711,14 +711,6 @@
return mClient->getLayerFrameStats(token, outStats);
}
-status_t SurfaceComposerClient::getTransformToDisplayInverse(const sp<IBinder>& token,
- bool* outTransformToDisplayInverse) const {
- if (mStatus != NO_ERROR) {
- return mStatus;
- }
- return mClient->getTransformToDisplayInverse(token, outTransformToDisplayInverse);
-}
-
inline Composer& SurfaceComposerClient::getComposer() {
return mComposer;
}
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 1e69379..7a68f11 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -209,13 +209,6 @@
return client->getLayerFrameStats(mHandle, outStats);
}
-status_t SurfaceControl::getTransformToDisplayInverse(bool* outTransformToDisplayInverse) const {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->getTransformToDisplayInverse(mHandle, outTransformToDisplayInverse);
-}
-
status_t SurfaceControl::validate() const
{
if (mHandle==0 || mClient==0) {
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index 5aa9652..f464411 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -24,81 +24,81 @@
DvrApi_v1* dvr_api = static_cast<DvrApi_v1*>(api);
// display_manager_client.h
- dvr_api->display_manager_client_create_ = dvrDisplayManagerClientCreate;
- dvr_api->display_manager_client_destroy_ = dvrDisplayManagerClientDestroy;
- dvr_api->display_manager_client_get_surface_list_ =
+ dvr_api->display_manager_client_create = dvrDisplayManagerClientCreate;
+ dvr_api->display_manager_client_destroy = dvrDisplayManagerClientDestroy;
+ dvr_api->display_manager_client_get_surface_list =
dvrDisplayManagerClientGetSurfaceList;
- dvr_api->display_manager_client_surface_list_destroy_ =
+ dvr_api->display_manager_client_surface_list_destroy =
dvrDisplayManagerClientSurfaceListDestroy;
- dvr_api->display_manager_setup_pose_buffer_ =
+ dvr_api->display_manager_setup_pose_buffer =
dvrDisplayManagerSetupPoseBuffer;
- dvr_api->display_manager_client_surface_list_get_size_ =
+ dvr_api->display_manager_client_surface_list_get_size =
dvrDisplayManagerClientSurfaceListGetSize;
- dvr_api->display_manager_client_surface_list_get_surface_id_ =
+ dvr_api->display_manager_client_surface_list_get_surface_id =
dvrDisplayManagerClientSurfaceListGetSurfaceId;
- dvr_api->display_manager_client_get_surface_buffer_list_ =
+ dvr_api->display_manager_client_get_surface_buffer_list =
dvrDisplayManagerClientGetSurfaceBuffers;
- dvr_api->display_manager_client_surface_buffer_list_destroy_ =
+ dvr_api->display_manager_client_surface_buffer_list_destroy =
dvrDisplayManagerClientSurfaceBuffersDestroy;
- dvr_api->display_manager_client_surface_buffer_list_get_size_ =
+ dvr_api->display_manager_client_surface_buffer_list_get_size =
dvrDisplayManagerClientSurfaceBuffersGetSize;
- dvr_api->display_manager_client_surface_buffer_list_get_fd_ =
+ dvr_api->display_manager_client_surface_buffer_list_get_fd =
dvrDisplayManagerClientSurfaceBuffersGetFd;
// dvr_buffer.h
- dvr_api->write_buffer_destroy_ = dvrWriteBufferDestroy;
- dvr_api->write_buffer_get_blob_fds_ = dvrWriteBufferGetBlobFds;
- dvr_api->write_buffer_get_AHardwareBuffer_ =
+ dvr_api->write_buffer_destroy = dvrWriteBufferDestroy;
+ dvr_api->write_buffer_get_blob_fds = dvrWriteBufferGetBlobFds;
+ dvr_api->write_buffer_get_ahardwarebuffer =
dvrWriteBufferGetAHardwareBuffer;
- dvr_api->write_buffer_post_ = dvrWriteBufferPost;
- dvr_api->write_buffer_gain_ = dvrWriteBufferGain;
- dvr_api->write_buffer_gain_async_ = dvrWriteBufferGainAsync;
+ dvr_api->write_buffer_post = dvrWriteBufferPost;
+ dvr_api->write_buffer_gain = dvrWriteBufferGain;
+ dvr_api->write_buffer_gain_async = dvrWriteBufferGainAsync;
- dvr_api->read_buffer_destroy_ = dvrReadBufferDestroy;
- dvr_api->read_buffer_get_blob_fds_ = dvrReadBufferGetBlobFds;
- dvr_api->read_buffer_get_AHardwareBuffer_ = dvrReadBufferGetAHardwareBuffer;
- dvr_api->read_buffer_acquire_ = dvrReadBufferAcquire;
- dvr_api->read_buffer_release_ = dvrReadBufferRelease;
- dvr_api->read_buffer_release_async_ = dvrReadBufferReleaseAsync;
+ dvr_api->read_buffer_destroy = dvrReadBufferDestroy;
+ dvr_api->read_buffer_get_blob_fds = dvrReadBufferGetBlobFds;
+ dvr_api->read_buffer_get_ahardwarebuffer = dvrReadBufferGetAHardwareBuffer;
+ dvr_api->read_buffer_acquire = dvrReadBufferAcquire;
+ dvr_api->read_buffer_release = dvrReadBufferRelease;
+ dvr_api->read_buffer_release_async = dvrReadBufferReleaseAsync;
// dvr_buffer_queue.h
- dvr_api->write_buffer_queue_destroy_ = dvrWriteBufferQueueDestroy;
- dvr_api->write_buffer_queue_get_capacity_ = dvrWriteBufferQueueGetCapacity;
- dvr_api->write_buffer_queue_get_external_surface_ =
+ dvr_api->write_buffer_queue_destroy = dvrWriteBufferQueueDestroy;
+ dvr_api->write_buffer_queue_get_capacity = dvrWriteBufferQueueGetCapacity;
+ dvr_api->write_buffer_queue_get_external_surface =
dvrWriteBufferQueueGetExternalSurface;
- dvr_api->write_buffer_queue_create_read_queue_ =
+ dvr_api->write_buffer_queue_create_read_queue =
dvrWriteBufferQueueCreateReadQueue;
- dvr_api->write_buffer_queue_dequeue_ = dvrWriteBufferQueueDequeue;
- dvr_api->read_buffer_queue_destroy_ = dvrReadBufferQueueDestroy;
- dvr_api->read_buffer_queue_get_capacity_ = dvrReadBufferQueueGetCapacity;
- dvr_api->read_buffer_queue_create_read_queue_ =
+ dvr_api->write_buffer_queue_dequeue = dvrWriteBufferQueueDequeue;
+ dvr_api->read_buffer_queue_destroy = dvrReadBufferQueueDestroy;
+ dvr_api->read_buffer_queue_get_capacity = dvrReadBufferQueueGetCapacity;
+ dvr_api->read_buffer_queue_create_read_queue =
dvrReadBufferQueueCreateReadQueue;
dvr_api->read_buffer_queue_dequeue = dvrReadBufferQueueDequeue;
// dvr_surface.h
- dvr_api->get_pose_buffer_ = dvrGetPoseBuffer;
- dvr_api->surface_create_ = dvrSurfaceCreate;
- dvr_api->surface_get_write_buffer_queue_ = dvrSurfaceGetWriteBufferQueue;
+ dvr_api->get_pose_buffer = dvrGetPoseBuffer;
+ dvr_api->surface_create = dvrSurfaceCreate;
+ dvr_api->surface_get_write_buffer_queue = dvrSurfaceGetWriteBufferQueue;
// vsync_client_api.h
- dvr_api->vsync_client_create_ = dvr_vsync_client_create;
- dvr_api->vsync_client_destroy_ = dvr_vsync_client_destroy;
- dvr_api->vsync_client_get_sched_info_ = dvr_vsync_client_get_sched_info;
+ dvr_api->vsync_client_create = dvr_vsync_client_create;
+ dvr_api->vsync_client_destroy = dvr_vsync_client_destroy;
+ dvr_api->vsync_client_get_sched_info = dvr_vsync_client_get_sched_info;
// pose_client.h
- dvr_api->pose_client_create_ = dvrPoseCreate;
- dvr_api->pose_client_destroy_ = dvrPoseDestroy;
- dvr_api->pose_get_ = dvrPoseGet;
- dvr_api->pose_get_vsync_count_ = dvrPoseGetVsyncCount;
- dvr_api->pose_get_controller_ = dvrPoseGetController;
+ dvr_api->pose_client_create = dvrPoseCreate;
+ dvr_api->pose_client_destroy = dvrPoseDestroy;
+ dvr_api->pose_get = dvrPoseGet;
+ dvr_api->pose_get_vsync_count = dvrPoseGetVsyncCount;
+ dvr_api->pose_get_controller = dvrPoseGetController;
// virtual_touchpad_client.h
- dvr_api->virtual_touchpad_create_ = dvrVirtualTouchpadCreate;
- dvr_api->virtual_touchpad_destroy_ = dvrVirtualTouchpadDestroy;
- dvr_api->virtual_touchpad_attach_ = dvrVirtualTouchpadAttach;
- dvr_api->virtual_touchpad_detach_ = dvrVirtualTouchpadDetach;
- dvr_api->virtual_touchpad_touch_ = dvrVirtualTouchpadTouch;
- dvr_api->virtual_touchpad_button_state_ = dvrVirtualTouchpadButtonState;
+ dvr_api->virtual_touchpad_create = dvrVirtualTouchpadCreate;
+ dvr_api->virtual_touchpad_destroy = dvrVirtualTouchpadDestroy;
+ dvr_api->virtual_touchpad_attach = dvrVirtualTouchpadAttach;
+ dvr_api->virtual_touchpad_detach = dvrVirtualTouchpadDetach;
+ dvr_api->virtual_touchpad_touch = dvrVirtualTouchpadTouch;
+ dvr_api->virtual_touchpad_button_state = dvrVirtualTouchpadButtonState;
return 0;
}
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index bee4d66..d840b6c 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -146,80 +146,80 @@
struct DvrApi_v1 {
// Display manager client
- DvrDisplayManagerClientCreatePtr display_manager_client_create_;
- DvrDisplayManagerClientDestroyPtr display_manager_client_destroy_;
+ DvrDisplayManagerClientCreatePtr display_manager_client_create;
+ DvrDisplayManagerClientDestroyPtr display_manager_client_destroy;
DvrDisplayManagerClientGetSurfaceListPtr
- display_manager_client_get_surface_list_;
+ display_manager_client_get_surface_list;
DvrDisplayManagerClientSurfaceListDestroyPtr
- display_manager_client_surface_list_destroy_;
- DvrDisplayManagerSetupPoseBufferPtr display_manager_setup_pose_buffer_;
+ display_manager_client_surface_list_destroy;
+ DvrDisplayManagerSetupPoseBufferPtr display_manager_setup_pose_buffer;
DvrDisplayManagerClientSurfaceListGetSizePtr
- display_manager_client_surface_list_get_size_;
+ display_manager_client_surface_list_get_size;
DvrDisplayManagerClientSurfaceListGetSurfaceIdPtr
- display_manager_client_surface_list_get_surface_id_;
+ display_manager_client_surface_list_get_surface_id;
DvrDisplayManagerClientGetSurfaceBufferListPtr
- display_manager_client_get_surface_buffer_list_;
+ display_manager_client_get_surface_buffer_list;
DvrDisplayManagerClientSurfaceBufferListDestroyPtr
- display_manager_client_surface_buffer_list_destroy_;
+ display_manager_client_surface_buffer_list_destroy;
DvrDisplayManagerClientSurfaceBufferListGetSizePtr
- display_manager_client_surface_buffer_list_get_size_;
+ display_manager_client_surface_buffer_list_get_size;
DvrDisplayManagerClientSurfaceBufferListGetFdPtr
- display_manager_client_surface_buffer_list_get_fd_;
+ display_manager_client_surface_buffer_list_get_fd;
// Write buffer
- DvrWriteBufferDestroyPtr write_buffer_destroy_;
- DvrWriteBufferGetBlobFdsPtr write_buffer_get_blob_fds_;
- DvrWriteBufferGetAHardwareBufferPtr write_buffer_get_AHardwareBuffer_;
- DvrWriteBufferPostPtr write_buffer_post_;
- DvrWriteBufferGainPtr write_buffer_gain_;
- DvrWriteBufferGainAsyncPtr write_buffer_gain_async_;
+ DvrWriteBufferDestroyPtr write_buffer_destroy;
+ DvrWriteBufferGetBlobFdsPtr write_buffer_get_blob_fds;
+ DvrWriteBufferGetAHardwareBufferPtr write_buffer_get_ahardwarebuffer;
+ DvrWriteBufferPostPtr write_buffer_post;
+ DvrWriteBufferGainPtr write_buffer_gain;
+ DvrWriteBufferGainAsyncPtr write_buffer_gain_async;
// Read buffer
- DvrReadBufferDestroyPtr read_buffer_destroy_;
- DvrReadBufferGetBlobFdsPtr read_buffer_get_blob_fds_;
- DvrReadBufferGetAHardwareBufferPtr read_buffer_get_AHardwareBuffer_;
- DvrReadBufferAcquirePtr read_buffer_acquire_;
- DvrReadBufferReleasePtr read_buffer_release_;
- DvrReadBufferReleaseAsyncPtr read_buffer_release_async_;
+ DvrReadBufferDestroyPtr read_buffer_destroy;
+ DvrReadBufferGetBlobFdsPtr read_buffer_get_blob_fds;
+ DvrReadBufferGetAHardwareBufferPtr read_buffer_get_ahardwarebuffer;
+ DvrReadBufferAcquirePtr read_buffer_acquire;
+ DvrReadBufferReleasePtr read_buffer_release;
+ DvrReadBufferReleaseAsyncPtr read_buffer_release_async;
// Write buffer queue
- DvrWriteBufferQueueDestroyPtr write_buffer_queue_destroy_;
- DvrWriteBufferQueueGetCapacityPtr write_buffer_queue_get_capacity_;
+ DvrWriteBufferQueueDestroyPtr write_buffer_queue_destroy;
+ DvrWriteBufferQueueGetCapacityPtr write_buffer_queue_get_capacity;
DvrWriteBufferQueueGetExternalSurfacePtr
- write_buffer_queue_get_external_surface_;
- DvrWriteBufferQueueCreateReadQueuePtr write_buffer_queue_create_read_queue_;
- DvrWriteBufferQueueDequeuePtr write_buffer_queue_dequeue_;
+ write_buffer_queue_get_external_surface;
+ DvrWriteBufferQueueCreateReadQueuePtr write_buffer_queue_create_read_queue;
+ DvrWriteBufferQueueDequeuePtr write_buffer_queue_dequeue;
// Read buffer queue
- DvrReadBufferQueueDestroyPtr read_buffer_queue_destroy_;
- DvrReadBufferQueueGetCapacityPtr read_buffer_queue_get_capacity_;
- DvrReadBufferQueueCreateReadQueuePtr read_buffer_queue_create_read_queue_;
+ DvrReadBufferQueueDestroyPtr read_buffer_queue_destroy;
+ DvrReadBufferQueueGetCapacityPtr read_buffer_queue_get_capacity;
+ DvrReadBufferQueueCreateReadQueuePtr read_buffer_queue_create_read_queue;
DvrReadBufferQueueDequeuePtr read_buffer_queue_dequeue;
// V-Sync client
- DvrVSyncClientCreatePtr vsync_client_create_;
- DvrVSyncClientDestroyPtr vsync_client_destroy_;
- DvrVSyncClientGetSchedInfoPtr vsync_client_get_sched_info_;
+ DvrVSyncClientCreatePtr vsync_client_create;
+ DvrVSyncClientDestroyPtr vsync_client_destroy;
+ DvrVSyncClientGetSchedInfoPtr vsync_client_get_sched_info;
// Display surface
- DvrGetPoseBufferPtr get_pose_buffer_;
- DvrSurfaceCreatePtr surface_create_;
- DvrSurfaceGetWriteBufferQueuePtr surface_get_write_buffer_queue_;
+ DvrGetPoseBufferPtr get_pose_buffer;
+ DvrSurfaceCreatePtr surface_create;
+ DvrSurfaceGetWriteBufferQueuePtr surface_get_write_buffer_queue;
// Pose client
- DvrPoseClientCreatePtr pose_client_create_;
- DvrPoseClientDestroyPtr pose_client_destroy_;
- DvrPoseGetPtr pose_get_;
- DvrPoseGetVsyncCountPtr pose_get_vsync_count_;
- DvrPoseGetControllerPtr pose_get_controller_;
+ DvrPoseClientCreatePtr pose_client_create;
+ DvrPoseClientDestroyPtr pose_client_destroy;
+ DvrPoseGetPtr pose_get;
+ DvrPoseGetVsyncCountPtr pose_get_vsync_count;
+ DvrPoseGetControllerPtr pose_get_controller;
// Virtual touchpad client
- DvrVirtualTouchpadCreatePtr virtual_touchpad_create_;
- DvrVirtualTouchpadDestroyPtr virtual_touchpad_destroy_;
- DvrVirtualTouchpadAttachPtr virtual_touchpad_attach_;
- DvrVirtualTouchpadDetachPtr virtual_touchpad_detach_;
- DvrVirtualTouchpadTouchPtr virtual_touchpad_touch_;
- DvrVirtualTouchpadButtonStatePtr virtual_touchpad_button_state_;
+ DvrVirtualTouchpadCreatePtr virtual_touchpad_create;
+ DvrVirtualTouchpadDestroyPtr virtual_touchpad_destroy;
+ DvrVirtualTouchpadAttachPtr virtual_touchpad_attach;
+ DvrVirtualTouchpadDetachPtr virtual_touchpad_detach;
+ DvrVirtualTouchpadTouchPtr virtual_touchpad_touch;
+ DvrVirtualTouchpadButtonStatePtr virtual_touchpad_button_state;
};
int dvrGetApi(void* api, size_t struct_size, int version);
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 9ddae2b..e9a2513 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -210,15 +210,5 @@
return NO_ERROR;
}
-status_t Client::getTransformToDisplayInverse(const sp<IBinder>& handle,
- bool* outTransformToDisplayInverse) const {
- sp<Layer> layer = getLayerUser(handle);
- if (layer == NULL) {
- return NAME_NOT_FOUND;
- }
- *outTransformToDisplayInverse = layer->getTransformToDisplayInverse();
- return NO_ERROR;
-}
-
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 141f6c7..b5f98b8 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -67,8 +67,6 @@
virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;
- virtual status_t getTransformToDisplayInverse(
- const sp<IBinder>& handle, bool* outTransformToDisplayInverse) const;
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ac7e083..16d8160 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -505,7 +505,7 @@
// which means using the inverse of the current transform set on the
// SurfaceFlingerConsumer.
uint32_t invTransform = mCurrentTransform;
- if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
+ if (getTransformToDisplayInverse()) {
/*
* the code below applies the primary display's inverse transform to the
* buffer
@@ -713,7 +713,7 @@
const Transform bufferOrientation(mCurrentTransform);
Transform transform(tr * t * bufferOrientation);
- if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
+ if (getTransformToDisplayInverse()) {
/*
* the code below applies the primary display's inverse transform to the
* buffer
@@ -725,8 +725,14 @@
invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
NATIVE_WINDOW_TRANSFORM_FLIP_H;
}
- // and apply to the current transform
- transform = Transform(invTransform) * transform;
+
+ /*
+ * Here we cancel out the orientation component of the WM transform.
+ * The scaling and translate components are already included in our bounds
+ * computation so it's enough to just omit it in the composition.
+ * See comment in onDraw with ref to b/36727915 for why.
+ */
+ transform = Transform(invTransform) * tr * bufferOrientation;
}
// this gives us only the "orientation" component of the transform
@@ -987,6 +993,24 @@
onDraw(hw, Region(hw->bounds()), false);
}
+static constexpr mat4 inverseOrientation(uint32_t transform) {
+ const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1);
+ const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1);
+ const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1);
+ mat4 tr;
+
+ if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ tr = tr * rot90;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+ tr = tr * flipH;
+ }
+ if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+ tr = tr * flipV;
+ }
+ return inverse(tr);
+}
+
void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
bool useIdentityTransform) const
{
@@ -1041,30 +1065,29 @@
mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
- if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
+ if (getTransformToDisplayInverse()) {
/*
* the code below applies the primary display's inverse transform to
* the texture transform
*/
-
- // create a 4x4 transform matrix from the display transform flags
- const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1);
- const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1);
- const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1);
-
- mat4 tr;
uint32_t transform =
DisplayDevice::getPrimaryDisplayOrientationTransform();
- if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90)
- tr = tr * rot90;
- if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H)
- tr = tr * flipH;
- if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V)
- tr = tr * flipV;
+ mat4 tr = inverseOrientation(transform);
- // calculate the inverse
- tr = inverse(tr);
+ /**
+ * TODO(b/36727915): This is basically a hack.
+ *
+ * Ensure that regardless of the parent transformation,
+ * this buffer is always transformed from native display
+ * orientation to display orientation. For example, in the case
+ * of a camera where the buffer remains in native orientation,
+ * we want the pixels to always be upright.
+ */
+ if (getParent() != nullptr) {
+ const auto parentTransform = getParent()->getTransform();
+ tr = tr * inverseOrientation(parentTransform.getOrientation());
+ }
// and finally apply it to the original texture matrix
const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
diff --git a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
index cb3e49d..45eabca 100644
--- a/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
+++ b/services/vr/hardware_composer/aidl/android/dvr/parcelable_composer_frame.cpp
@@ -19,6 +19,12 @@
status_t ret = parcel->writeUint64(frame_.display_id);
if (ret != OK) return ret;
+ ret = parcel->writeInt32(frame_.display_width);
+ if (ret != OK) return ret;
+
+ ret = parcel->writeInt32(frame_.display_height);
+ if (ret != OK) return ret;
+
ret = parcel->writeBool(frame_.removed);
if (ret != OK) return ret;
@@ -35,6 +41,12 @@
status_t ret = parcel->readUint64(&frame_.display_id);
if (ret != OK) return ret;
+ ret = parcel->readInt32(&frame_.display_width);
+ if (ret != OK) return ret;
+
+ ret = parcel->readInt32(&frame_.display_height);
+ if (ret != OK) return ret;
+
ret = parcel->readBool(&frame_.removed);
if (ret != OK) return ret;
diff --git a/services/vr/hardware_composer/tests/vr_composer_test.cpp b/services/vr/hardware_composer/tests/vr_composer_test.cpp
index cfc2708..d082f4b 100644
--- a/services/vr/hardware_composer/tests/vr_composer_test.cpp
+++ b/services/vr/hardware_composer/tests/vr_composer_test.cpp
@@ -104,6 +104,8 @@
ComposerView::Frame frame;
frame.display_id = 1;
frame.removed = false;
+ frame.display_width = 600;
+ frame.display_height = 400;
frame.layers.push_back(ComposerView::ComposerLayer{
.id = 1,
.buffer = CreateBuffer(),
@@ -120,6 +122,8 @@
ComposerView::Frame received_frame = callback->last_frame();
ASSERT_EQ(frame.display_id, received_frame.display_id);
+ ASSERT_EQ(frame.display_width, received_frame.display_width);
+ ASSERT_EQ(frame.display_height, received_frame.display_height);
ASSERT_EQ(frame.removed, received_frame.removed);
ASSERT_EQ(1u, received_frame.layers.size());
ASSERT_EQ(frame.layers[0].id, received_frame.layers[0].id);
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
index 8aa2fd5..3393ade 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -81,9 +81,35 @@
return buffer;
}
+void GetPrimaryDisplaySize(int32_t* width, int32_t* height) {
+ *width = 1080;
+ *height = 1920;
+
+ int error = 0;
+ auto display_client = DisplayClient::Create(&error);
+ SystemDisplayMetrics metrics;
+
+ if (error) {
+ ALOGE("Could not connect to display service : %s(%d)", strerror(error),
+ error);
+ return;
+ }
+
+ error = display_client->GetDisplayMetrics(&metrics);
+ if (error) {
+ ALOGE("Could not get display metrics from display service : %s(%d)",
+ strerror(error), error);
+ return;
+ }
+
+ *width = metrics.display_native_width;
+ *height = metrics.display_native_height;
+}
+
} // namespace
-HwcDisplay::HwcDisplay() {}
+HwcDisplay::HwcDisplay(int32_t width, int32_t height)
+ : width_(width), height_(height) {}
HwcDisplay::~HwcDisplay() {}
@@ -222,7 +248,7 @@
////////////////////////////////////////////////////////////////////////////////
// VrHwcClient
-VrHwc::VrHwc() { displays_[kDefaultDisplayId].reset(new HwcDisplay()); }
+VrHwc::VrHwc() {}
VrHwc::~VrHwc() {}
@@ -235,6 +261,14 @@
void VrHwc::enableCallback(bool enable) {
if (enable && client_ != nullptr) {
+ {
+ int32_t width, height;
+ GetPrimaryDisplaySize(&width, &height);
+ std::lock_guard<std::mutex> guard(mutex_);
+ // Create the primary display late to avoid initialization issues between
+ // VR HWC and SurfaceFlinger.
+ displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
+ }
client_.promote()->onHotplug(kDefaultDisplayId,
IComposerCallback::Connection::CONNECTED);
}
@@ -246,7 +280,7 @@
PixelFormat* format, Display* outDisplay) {
*format = PixelFormat::RGBA_8888;
*outDisplay = display_count_;
- displays_[display_count_].reset(new HwcDisplay());
+ displays_[display_count_].reset(new HwcDisplay(width, height));
display_count_++;
return Error::NONE;
}
@@ -308,41 +342,20 @@
IComposerClient::Attribute attribute,
int32_t* outValue) {
std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr) {
return Error::BAD_DISPLAY;
+ }
if (config != kDefaultConfigId) {
return Error::BAD_CONFIG;
}
- int error = 0;
- auto display_client = DisplayClient::Create(&error);
- SystemDisplayMetrics metrics;
-
- if (error) {
- ALOGE("Could not connect to display service : %s(%d)", strerror(error),
- error);
- } else {
- error = display_client->GetDisplayMetrics(&metrics);
-
- if (error) {
- ALOGE("Could not get display metrics from display service : %s(%d)",
- strerror(error), error);
- }
- }
-
- if (error) {
- metrics.display_native_width = 1080;
- metrics.display_native_height = 1920;
- ALOGI("Setting display metrics to default : width=%d height=%d",
- metrics.display_native_width, metrics.display_native_height);
- }
-
switch (attribute) {
case IComposerClient::Attribute::WIDTH:
- *outValue = metrics.display_native_width;
+ *outValue = display_ptr->width();
break;
case IComposerClient::Attribute::HEIGHT:
- *outValue = metrics.display_native_height;
+ *outValue = display_ptr->height();
break;
case IComposerClient::Attribute::VSYNC_PERIOD:
*outValue = 1000 * 1000 * 1000 / 30; // 30fps
@@ -510,6 +523,8 @@
std::vector<Layer> last_frame_layers;
Error status = display_ptr->GetFrame(&frame.layers);
frame.display_id = display;
+ frame.display_width = display_ptr->width();
+ frame.display_height = display_ptr->height();
if (status != Error::NONE)
return status;
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.h b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
index 3c76120..bfca9a6 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
@@ -74,6 +74,8 @@
// being removed, or left false in the case of a normal frame. The upper
// layer tracks display IDs and will handle new ones showing up.
bool removed = false;
+ int32_t display_width;
+ int32_t display_height;
std::vector<ComposerLayer> layers;
};
@@ -107,9 +109,12 @@
class HwcDisplay {
public:
- HwcDisplay();
+ HwcDisplay(int32_t width, int32_t height);
~HwcDisplay();
+ int32_t width() const { return width_; }
+ int32_t height() const { return height_; }
+
HwcLayer* CreateLayer();
bool DestroyLayer(Layer id);
HwcLayer* GetLayer(Layer id);
@@ -138,6 +143,9 @@
// Layer ID generator.
uint64_t layer_ids_ = 1;
+ int32_t width_;
+ int32_t height_;
+
HwcDisplay(const HwcDisplay&) = delete;
void operator=(const HwcDisplay&) = delete;
};
diff --git a/services/vr/vr_window_manager/display_view.cpp b/services/vr/vr_window_manager/display_view.cpp
index 311e27f..52984b7 100644
--- a/services/vr/vr_window_manager/display_view.cpp
+++ b/services/vr/vr_window_manager/display_view.cpp
@@ -168,8 +168,7 @@
void DisplayView::DrawEye(EyeType /* eye */, const mat4& perspective,
const mat4& eye_matrix, const mat4& head_matrix,
- const vec2& size, float fade_value) {
- size_ = size;
+ float fade_value) {
scale_ = GetScalingMatrix(size_.x(), size_.y());
DrawOverlays(perspective, eye_matrix, head_matrix, fade_value);
@@ -204,6 +203,7 @@
base::unique_fd DisplayView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame,
bool debug_mode, bool is_vr_active,
bool* showing) {
+ size_ = vec2(frame->display_width(), frame->display_height());
uint32_t app = current_vr_app_;
ViewMode visibility = CalculateVisibilityFromLayerConfig(*frame.get(), &app);
diff --git a/services/vr/vr_window_manager/display_view.h b/services/vr/vr_window_manager/display_view.h
index aaf4677..ad624c6 100644
--- a/services/vr/vr_window_manager/display_view.h
+++ b/services/vr/vr_window_manager/display_view.h
@@ -29,7 +29,7 @@
void OnDrawFrame(SurfaceFlingerView* surface_flinger_view, bool debug_mode);
void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix,
- const mat4& head_matrix, const vec2& size, float fade_value);
+ const mat4& head_matrix, float fade_value);
void Recenter(const mat4& initial);
@@ -43,6 +43,7 @@
const vec2& hit_location() const { return hit_location_in_window_coord_; }
uint32_t id() const { return id_; }
int touchpad_id() const { return touchpad_id_; }
+ vec2 size() const { return size_; }
void set_2dmode(bool mode) { use_2dmode_ = mode; }
void set_always_2d(bool mode) { always_2d_ = mode; }
diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp
index 2d2a85c..19b220b 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -56,12 +56,18 @@
}
return client_->OnFrame(std::make_unique<Frame>(
- std::move(hwc_frame), display_frame.display_id, display_frame.removed));
+ std::move(hwc_frame), display_frame.display_id, display_frame.removed,
+ display_frame.display_width, display_frame.display_height));
}
HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers, uint32_t display_id,
- bool removed)
- : display_id_(display_id), removed_(removed), layers_(std::move(layers)) {}
+ bool removed, int32_t display_width,
+ int32_t display_height)
+ : display_id_(display_id),
+ removed_(removed),
+ display_width_(display_width),
+ display_height_(display_height),
+ layers_(std::move(layers)) {}
HwcCallback::FrameStatus HwcCallback::Frame::Finish() {
if (status_ == FrameStatus::kUnfinished)
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index b8aa51b..c0d965a 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -81,16 +81,21 @@
class Frame {
public:
- Frame(std::vector<HwcLayer>&& layers, uint32_t display_id, bool removed);
+ Frame(std::vector<HwcLayer>&& layers, uint32_t display_id, bool removed,
+ int32_t display_width, int32_t display_height);
FrameStatus Finish();
const std::vector<HwcLayer>& layers() const { return layers_; }
uint32_t display_id() const { return display_id_; }
bool removed() const { return removed_; }
+ int32_t display_width() const { return display_width_; }
+ int32_t display_height() const { return display_height_; }
private:
uint32_t display_id_;
bool removed_;
+ int32_t display_width_;
+ int32_t display_height_;
std::vector<HwcLayer> layers_;
FrameStatus status_ = FrameStatus::kUnfinished;
};
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 3aae228..850f604 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -194,8 +194,11 @@
result.append("[displays]\n");
result.appendFormat("count = %zu\n", displays_.size());
- for (size_t i = 0; i < displays_.size(); ++i)
- result.appendFormat(" display_id = %" PRId32 "\n", displays_[i]->id());
+ for (size_t i = 0; i < displays_.size(); ++i) {
+ result.appendFormat(" display_id = %" PRId32 "\n", displays_[i]->id());
+ result.appendFormat(" size=%fx%f\n",
+ displays_[i]->size().x(), displays_[i]->size().y());
+ }
result.append("\n");
}
@@ -327,12 +330,9 @@
should_recenter_ = false;
}
- size_ = vec2(surface_flinger_view_->width(), surface_flinger_view_->height());
-
for (auto& display : displays_) {
if (display->visible()) {
- display->DrawEye(eye, perspective, eye_matrix, head_matrix, size_,
- fade_value_);
+ display->DrawEye(eye, perspective, eye_matrix, head_matrix, fade_value_);
}
}
@@ -481,9 +481,10 @@
return;
const vec2& hit_location = active_display_->hit_location();
+ const vec2 size = active_display_->size();
- float x = hit_location.x() / size_.x();
- float y = hit_location.y() / size_.y();
+ float x = hit_location.x() / size.x();
+ float y = hit_location.y() / size.y();
// Device is portrait, but in landscape when in VR.
// Rotate touch input appropriately.
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index 8548dc1..be2ae58 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -83,7 +83,6 @@
bool is_touching_ = false;
int touchpad_buttons_ = 0;
- vec2 size_;
// Used to center the scene when the shell becomes visible.
bool should_recenter_ = true;
diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp
index 7ecc542..c0ee1fc 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -1,7 +1,6 @@
#include "surface_flinger_view.h"
#include <impl/vr_composer_view.h>
-#include <private/dvr/display_client.h>
#include <private/dvr/native_buffer.h>
#include "hwc_callback.h"
@@ -34,33 +33,6 @@
return false;
}
- vr_composer_view_ =
- std::make_unique<VrComposerView>(std::make_unique<HwcCallback>(client));
- vr_composer_view_->Initialize(GetComposerViewFromIComposer(
- vr_hwcomposer_.get()));
-
- int error = 0;
- auto display_client = DisplayClient::Create(&error);
- SystemDisplayMetrics metrics;
-
- if (error) {
- ALOGE("Could not connect to display service : %s(%d)", strerror(error), error);
- } else {
- error = display_client->GetDisplayMetrics(&metrics);
-
- if (error) {
- ALOGE("Could not get display metrics from display service : %s(%d)", strerror(error), error);
- }
- }
-
- if (error) {
- metrics.display_native_height = 1920;
- metrics.display_native_width = 1080;
- ALOGI("Setting display metrics to default : width=%d height=%d", metrics.display_native_height, metrics.display_native_width);
- }
-
- width_ = metrics.display_native_width;
- height_ = metrics.display_native_height;
return true;
}
diff --git a/services/vr/vr_window_manager/surface_flinger_view.h b/services/vr/vr_window_manager/surface_flinger_view.h
index 7370299..3ea2b21 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.h
+++ b/services/vr/vr_window_manager/surface_flinger_view.h
@@ -26,9 +26,6 @@
SurfaceFlingerView();
~SurfaceFlingerView();
- int width() const { return width_; }
- int height() const { return height_; }
-
bool Initialize(HwcCallback::Client *client);
bool GetTextures(const HwcCallback::Frame& layers,
@@ -39,8 +36,6 @@
private:
sp<IComposer> vr_hwcomposer_;
std::unique_ptr<VrComposerView> vr_composer_view_;
- int width_ = 0;
- int height_ = 0;
SurfaceFlingerView(const SurfaceFlingerView&) = delete;
void operator=(const SurfaceFlingerView&) = delete;