Merge "Disable broken tests" into sc-dev
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index a546236..3f180d9 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -47,6 +47,9 @@
"libutils",
"server_configurable_flags",
],
+ static_libs: [
+ "libasync_safe",
+ ],
export_shared_lib_headers: [
"libbinder",
],
@@ -250,6 +253,7 @@
],
static_libs: [
+ "libasync_safe",
"libdiskusage",
"libotapreoptparameters",
],
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 0cf50a3..204953c 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -36,6 +36,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <async_safe/log.h>
#include <cutils/fs.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
@@ -727,7 +728,8 @@
if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
if (errno != EWOULDBLOCK) {
- PLOG(WARNING) << "Error locking profile " << package_name;
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Error locking profile %s: %d",
+ package_name.c_str(), errno);
}
// This implies that the app owning this profile is running
// (and has acquired the lock).
@@ -735,13 +737,15 @@
// The app never acquires the lock for the reference profiles of primary apks.
// Only dex2oat from installd will do that. Since installd is single threaded
// we should not see this case. Nevertheless be prepared for it.
- PLOG(WARNING) << "Failed to flock " << package_name;
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Failed to flock %s: %d",
+ package_name.c_str(), errno);
return false;
}
bool truncated = ftruncate(out_fd.get(), 0) == 0;
if (!truncated) {
- PLOG(WARNING) << "Could not truncate " << package_name;
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Could not truncate %s: %d",
+ package_name.c_str(), errno);
}
// Copy over data.
@@ -755,7 +759,8 @@
write(out_fd.get(), buffer, bytes);
}
if (flock(out_fd.get(), LOCK_UN) != 0) {
- PLOG(WARNING) << "Error unlocking profile " << package_name;
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Error unlocking profile %s: %d",
+ package_name.c_str(), errno);
}
// Use _exit since we don't want to run the global destructors in the child.
// b/62597429
@@ -1513,7 +1518,8 @@
// Validate the path structure.
if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
- LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not validate secondary dex path %s", dex_path.c_str());
_exit(kSecondaryDexDexoptAnalyzerSkippedValidatePath);
}
@@ -1809,7 +1815,8 @@
drop_capabilities(uid);
if (flock(out_oat.fd(), LOCK_EX | LOCK_NB) != 0) {
- PLOG(ERROR) << "flock(" << out_oat.path() << ") failed";
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "flock(%s) failed",
+ out_oat.path().c_str());
_exit(DexoptReturnCodes::kFlock);
}
@@ -1904,7 +1911,8 @@
const char* volume_uuid_cstr = volume_uuid ? volume_uuid->c_str() : nullptr;
if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr,
uid, storage_flag)) {
- LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not validate secondary dex path %s", dex_path.c_str());
_exit(kReconcileSecondaryDexValidationError);
}
@@ -1917,7 +1925,8 @@
case kSecondaryDexAccessIOError: _exit(kReconcileSecondaryDexAccessIOError);
case kSecondaryDexAccessPermissionError: _exit(kReconcileSecondaryDexValidationError);
default:
- LOG(ERROR) << "Unexpected result from check_secondary_dex_access: " << access_check;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Unexpected result from check_secondary_dex_access: %d", access_check);
_exit(kReconcileSecondaryDexValidationError);
}
@@ -1930,7 +1939,7 @@
std::string error_msg;
if (!create_secondary_dex_oat_layout(
dex_path,isas[i], oat_dir, oat_isa_dir, oat_path, &error_msg)) {
- LOG(ERROR) << error_msg;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "%s", error_msg.c_str());
_exit(kReconcileSecondaryDexValidationError);
}
@@ -1957,7 +1966,8 @@
result = rmdir_if_empty(oat_dir) && result;
}
if (!result) {
- PLOG(ERROR) << "Failed to clean secondary dex artifacts for location " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not validate secondary dex path %s", dex_path.c_str());
}
_exit(result ? kReconcileSecondaryDexCleanedUp : kReconcileSecondaryDexAccessIOError);
}
@@ -2030,7 +2040,8 @@
pipe_read.reset();
if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr, uid, storage_flag)) {
- LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Could not validate secondary dex path %s", dex_path.c_str());
_exit(DexoptReturnCodes::kHashValidatePath);
}
@@ -2041,6 +2052,8 @@
_exit(0);
}
PLOG(ERROR) << "Failed to open secondary dex " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Failed to open secondary dex %s: %d", dex_path.c_str(), errno);
_exit(DexoptReturnCodes::kHashOpenPath);
}
@@ -2053,7 +2066,8 @@
if (bytes_read == 0) {
break;
} else if (bytes_read == -1) {
- PLOG(ERROR) << "Failed to read secondary dex " << dex_path;
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Failed to read secondary dex %s: %d", dex_path.c_str(), errno);
_exit(DexoptReturnCodes::kHashReadDex);
}
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index f67ab81..7082017 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -20,6 +20,7 @@
"libcutils",
],
static_libs: [
+ "libasync_safe",
"libdiskusage",
"libinstalld",
"liblog",
@@ -44,6 +45,7 @@
"server_configurable_flags",
],
static_libs: [
+ "libasync_safe",
"libdiskusage",
"libinstalld",
"liblog",
@@ -84,6 +86,7 @@
"server_configurable_flags",
],
static_libs: [
+ "libasync_safe",
"libdiskusage",
"libinstalld",
"liblog",
@@ -124,6 +127,7 @@
"server_configurable_flags",
],
static_libs: [
+ "libasync_safe",
"libdiskusage",
"libinstalld",
"liblog",
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index 8d1bf99..c3d3a4b 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -739,6 +739,9 @@
* skipping frames in an image with such frames may not produce the correct
* results.
*
+ * Only supported by {@link ANDROID_BITMAP_FORMAT_RGBA_8888} and
+ * {@link ANDROID_BITMAP_FORMAT_RGBA_F16}.
+ *
* @param decoder an {@link AImageDecoder} object.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
* indicating the reason for the failure.
@@ -747,6 +750,8 @@
* - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The AImageDecoder
* represents an image that is not animated (see
* {@link AImageDecoder_isAnimated}) or the AImageDecoder is null.
+ * - {@link ANDROID_IMAGE_DECODER_INVALID_STATE): The requested
+ * {@link AndroidBitmapFormat} does not support animation.
* - {@link ANDROID_IMAGE_DECODER_INCOMPLETE}: The input appears
* to be truncated. The client must call {@link AImageDecoder_rewind}
* before calling {@link AImageDecoder_decodeImage} again.
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index b7eafcd..f6c2e55 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -534,11 +534,12 @@
*
* \param compatibility The frame rate compatibility of this surface. The compatibility value may
* influence the system's choice of display frame rate. To specify a compatibility use the
- * ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* enum.
+ * ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* enum. This parameter is ignored when frameRate is 0.
*
- * \param changeFrameRateStrategy Whether display refresh rate transitions should be seamless.
- * A seamless transition is one that doesn't have any visual interruptions, such as a black
- * screen for a second or two. See the ANATIVEWINDOW_CHANGE_FRAME_RATE_* values.
+ * \param changeFrameRateStrategy Whether display refresh rate transitions caused by this
+ * surface should be seamless. A seamless transition is one that doesn't have any visual
+ * interruptions, such as a black screen for a second or two. See the
+ * ANATIVEWINDOW_CHANGE_FRAME_RATE_* values. This parameter is ignored when frameRate is 0.
*
* Available since API level 31.
*/
diff --git a/libs/binder/PermissionCache.cpp b/libs/binder/PermissionCache.cpp
index 6eae5ef..670fd55 100644
--- a/libs/binder/PermissionCache.cpp
+++ b/libs/binder/PermissionCache.cpp
@@ -109,5 +109,10 @@
return granted;
}
+void PermissionCache::purgeCache() {
+ PermissionCache& pc(PermissionCache::getInstance());
+ pc.purge();
+}
+
// ---------------------------------------------------------------------------
} // namespace android
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp
index 1388a80..f2302f7 100644
--- a/libs/binder/RpcConnection.cpp
+++ b/libs/binder/RpcConnection.cpp
@@ -130,24 +130,21 @@
#endif // __BIONIC__
-class SocketAddressImpl : public RpcConnection::SocketAddress {
+class InetSocketAddress : public RpcConnection::SocketAddress {
public:
- SocketAddressImpl(const sockaddr* addr, size_t size, const String8& desc)
- : mAddr(addr), mSize(size), mDesc(desc) {}
+ InetSocketAddress(const sockaddr* sockAddr, size_t size, const char* addr, unsigned int port)
+ : mSockAddr(sockAddr), mSize(size), mAddr(addr), mPort(port) {}
[[nodiscard]] std::string toString() const override {
- return std::string(mDesc.c_str(), mDesc.size());
+ return String8::format("%s:%u", mAddr, mPort).c_str();
}
- [[nodiscard]] const sockaddr* addr() const override { return mAddr; }
+ [[nodiscard]] const sockaddr* addr() const override { return mSockAddr; }
[[nodiscard]] size_t addrSize() const override { return mSize; }
- void set(const sockaddr* addr, size_t size) {
- mAddr = addr;
- mSize = size;
- }
private:
- const sockaddr* mAddr = nullptr;
- size_t mSize = 0;
- String8 mDesc;
+ const sockaddr* mSockAddr;
+ size_t mSize;
+ const char* mAddr;
+ unsigned int mPort;
};
AddrInfo GetAddrInfo(const char* addr, unsigned int port) {
@@ -170,14 +167,15 @@
}
bool RpcConnection::setupInetServer(unsigned int port) {
- auto aiStart = GetAddrInfo("127.0.0.1", port);
+ const char* kAddr = "127.0.0.1";
+
+ auto aiStart = GetAddrInfo(kAddr, port);
if (aiStart == nullptr) return false;
- SocketAddressImpl socketAddress(nullptr, 0, String8::format("127.0.0.1:%u", port));
for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
- socketAddress.set(ai->ai_addr, ai->ai_addrlen);
+ InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
if (setupSocketServer(socketAddress)) return true;
}
- ALOGE("None of the socket address resolved for 127.0.0.1:%u can be set up as inet server.",
+ ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
port);
return false;
}
@@ -185,9 +183,8 @@
bool RpcConnection::addInetClient(const char* addr, unsigned int port) {
auto aiStart = GetAddrInfo(addr, port);
if (aiStart == nullptr) return false;
- SocketAddressImpl socketAddress(nullptr, 0, String8::format("%s:%u", addr, port));
for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
- socketAddress.set(ai->ai_addr, ai->ai_addrlen);
+ InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, addr, port);
if (addSocketClient(socketAddress)) return true;
}
ALOGE("None of the socket address resolved for %s:%u can be added as inet client.", addr, port);
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 1fa37ba..9a0be92 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -30,8 +30,6 @@
namespace android {
-using base::unique_fd;
-
RpcServer::RpcServer() {}
RpcServer::~RpcServer() {}
@@ -48,16 +46,20 @@
auto connection = RpcConnection::make();
connection->setForServer(sp<RpcServer>::fromExisting(this));
- mConnections.push_back(connection);
+ {
+ std::lock_guard<std::mutex> _l(mLock);
+ mConnections.push_back(connection);
+ }
return connection;
}
void RpcServer::setRootObject(const sp<IBinder>& binder) {
- LOG_ALWAYS_FATAL_IF(mRootObject != nullptr, "There can only be one root object");
+ std::lock_guard<std::mutex> _l(mLock);
mRootObject = binder;
}
sp<IBinder> RpcServer::getRootObject() {
+ std::lock_guard<std::mutex> _l(mLock);
return mRootObject;
}
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 31f63c8..52f221d 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -49,39 +49,39 @@
{
public:
enum {
- FIRST_CALL_TRANSACTION = 0x00000001,
- LAST_CALL_TRANSACTION = 0x00ffffff,
+ FIRST_CALL_TRANSACTION = 0x00000001,
+ LAST_CALL_TRANSACTION = 0x00ffffff,
- PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'),
- DUMP_TRANSACTION = B_PACK_CHARS('_','D','M','P'),
- SHELL_COMMAND_TRANSACTION = B_PACK_CHARS('_','C','M','D'),
- INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
- SYSPROPS_TRANSACTION = B_PACK_CHARS('_', 'S', 'P', 'R'),
- EXTENSION_TRANSACTION = B_PACK_CHARS('_', 'E', 'X', 'T'),
- DEBUG_PID_TRANSACTION = B_PACK_CHARS('_', 'P', 'I', 'D'),
+ PING_TRANSACTION = B_PACK_CHARS('_', 'P', 'N', 'G'),
+ DUMP_TRANSACTION = B_PACK_CHARS('_', 'D', 'M', 'P'),
+ SHELL_COMMAND_TRANSACTION = B_PACK_CHARS('_', 'C', 'M', 'D'),
+ INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
+ SYSPROPS_TRANSACTION = B_PACK_CHARS('_', 'S', 'P', 'R'),
+ EXTENSION_TRANSACTION = B_PACK_CHARS('_', 'E', 'X', 'T'),
+ DEBUG_PID_TRANSACTION = B_PACK_CHARS('_', 'P', 'I', 'D'),
// See android.os.IBinder.TWEET_TRANSACTION
// Most importantly, messages can be anything not exceeding 130 UTF-8
// characters, and callees should exclaim "jolly good message old boy!"
- TWEET_TRANSACTION = B_PACK_CHARS('_', 'T', 'W', 'T'),
+ TWEET_TRANSACTION = B_PACK_CHARS('_', 'T', 'W', 'T'),
// See android.os.IBinder.LIKE_TRANSACTION
// Improve binder self-esteem.
- LIKE_TRANSACTION = B_PACK_CHARS('_', 'L', 'I', 'K'),
+ LIKE_TRANSACTION = B_PACK_CHARS('_', 'L', 'I', 'K'),
// Corresponds to TF_ONE_WAY -- an asynchronous call.
- FLAG_ONEWAY = 0x00000001,
+ FLAG_ONEWAY = 0x00000001,
// Corresponds to TF_CLEAR_BUF -- clear transaction buffers after call
// is made
- FLAG_CLEAR_BUF = 0x00000020,
+ FLAG_CLEAR_BUF = 0x00000020,
// Private userspace flag for transaction which is being requested from
// a vendor context.
- FLAG_PRIVATE_VENDOR = 0x10000000,
+ FLAG_PRIVATE_VENDOR = 0x10000000,
};
- IBinder();
+ IBinder();
/**
* Check if this IBinder implements the interface named by
diff --git a/libs/binder/include/binder/PermissionCache.h b/libs/binder/include/binder/PermissionCache.h
index 835a3a8..21aa705 100644
--- a/libs/binder/include/binder/PermissionCache.h
+++ b/libs/binder/include/binder/PermissionCache.h
@@ -73,6 +73,8 @@
static bool checkPermission(const String16& permission,
pid_t pid, uid_t uid);
+
+ static void purgeCache();
};
// ---------------------------------------------------------------------------
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index d29b651..a665fad 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -21,6 +21,8 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <mutex>
+
// WARNING: This is a feature which is still in development, and it is subject
// to radical change. Any production use of this may subject your code to any
// number of problems.
@@ -30,9 +32,6 @@
/**
* This represents a server of an interface, which may be connected to by any
* number of clients over sockets.
- *
- * This object is not (currently) thread safe. All calls to it are expected to
- * happen at process startup.
*/
class RpcServer final : public virtual RefBase {
public:
@@ -51,16 +50,8 @@
sp<RpcConnection> addClientConnection();
/**
- * Allowing a server to explicitly drop clients would be easy to add here,
- * but it is not currently implemented, since users of this functionality
- * could not use similar functionality if they are running under real
- * binder.
- */
- // void drop(const sp<RpcConnection>& connection);
-
- /**
* The root object can be retrieved by any client, without any
- * authentication.
+ * authentication. TODO(b/183988761)
*/
void setRootObject(const sp<IBinder>& binder);
@@ -77,8 +68,8 @@
bool mAgreedExperimental = false;
+ std::mutex mLock;
sp<IBinder> mRootObject;
-
std::vector<sp<RpcConnection>> mConnections; // per-client
};
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index eb103d3..b03e24c 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -55,7 +55,9 @@
defaults: ["libbinder_ndk_host_user"],
host_supported: true,
- llndk_stubs: "libbinder_ndk.llndk",
+ llndk: {
+ symbol_file: "libbinder_ndk.map.txt",
+ },
export_include_dirs: [
"include_cpp",
@@ -192,13 +194,3 @@
symbol_file: "libbinder_ndk.map.txt",
first_version: "29",
}
-
-llndk_library {
- name: "libbinder_ndk.llndk",
- symbol_file: "libbinder_ndk.map.txt",
- export_include_dirs: [
- "include_cpp",
- "include_ndk",
- "include_platform",
- ],
-}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index f303b7c..c0f7c99 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -35,6 +35,7 @@
name: "binderDriverInterfaceTest_IPC_32",
defaults: ["binder_test_defaults"],
srcs: ["binderDriverInterfaceTest.cpp"],
+ header_libs: ["libbinder_headers"],
compile_multilib: "32",
multilib: { lib32: { suffix: "" } },
cflags: ["-DBINDER_IPC_32BIT=1"],
@@ -49,7 +50,7 @@
cflags: ["-DBINDER_IPC_32BIT=1"],
},
},
-
+ header_libs: ["libbinder_headers"],
srcs: ["binderDriverInterfaceTest.cpp"],
test_suites: ["device-tests", "vts"],
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 517b49e..267db76 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -98,7 +98,6 @@
SAFE_PARCEL(output.write, transparentRegion);
SAFE_PARCEL(output.writeUint32, transform);
SAFE_PARCEL(output.writeBool, transformToDisplayInverse);
- SAFE_PARCEL(output.write, crop);
SAFE_PARCEL(output.write, orientedDisplaySpaceRect);
if (buffer) {
@@ -167,6 +166,7 @@
}
SAFE_PARCEL(output.write, stretchEffect);
+ SAFE_PARCEL(output.write, bufferCrop);
return NO_ERROR;
}
@@ -209,7 +209,6 @@
SAFE_PARCEL(input.read, transparentRegion);
SAFE_PARCEL(input.readUint32, &transform);
SAFE_PARCEL(input.readBool, &transformToDisplayInverse);
- SAFE_PARCEL(input.read, crop);
SAFE_PARCEL(input.read, orientedDisplaySpaceRect);
bool tmpBool = false;
@@ -296,6 +295,7 @@
}
SAFE_PARCEL(input.read, stretchEffect);
+ SAFE_PARCEL(input.read, bufferCrop);
return NO_ERROR;
}
@@ -539,6 +539,10 @@
what |= eStretchChanged;
stretchEffect = other.stretchEffect;
}
+ if (other.what & eBufferCropChanged) {
+ what |= eBufferCropChanged;
+ bufferCrop = other.bufferCrop;
+ }
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
"other.what=0x%" PRIu64 " what=0x%" PRIu64,
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 5db0eae..808b731 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1664,6 +1664,21 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBufferCrop(
+ const sp<SurfaceControl>& sc, const Rect& bufferCrop) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eBufferCropChanged;
+ s->bufferCrop = bufferCrop;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
diff --git a/libs/gui/include/gui/JankInfo.h b/libs/gui/include/gui/JankInfo.h
index 85ae9cb..ce9716f 100644
--- a/libs/gui/include/gui/JankInfo.h
+++ b/libs/gui/include/gui/JankInfo.h
@@ -42,6 +42,10 @@
BufferStuffing = 0x40,
// Jank due to unknown reasons.
Unknown = 0x80,
+ // SF is said to be stuffed if the previous frame ran longer than expected resulting in the case
+ // where the previous frame was presented in the current frame's expected vsync. This pushes the
+ // current frame to the next vsync. The behavior is similar to BufferStuffing.
+ SurfaceFlingerStuffing = 0x100,
};
} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index b4f62f2..3947f22 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -85,7 +85,7 @@
eReleaseBufferListenerChanged = 0x00000400,
eShadowRadiusChanged = 0x00000800,
eLayerCreated = 0x00001000,
- /* was eDetachChildren, now available 0x00002000, */
+ eBufferCropChanged = 0x00002000,
eRelativeLayerChanged = 0x00004000,
eReparent = 0x00008000,
eColorChanged = 0x00010000,
@@ -227,6 +227,8 @@
// Stretch effect to be applied to this layer
StretchEffect stretchEffect;
+ Rect bufferCrop;
+
// Listens to when the buffer is safe to be released. This is used for blast
// layers only. The callback includes a release fence as well as the graphic
// buffer id to identify the buffer.
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 5bbd8e3..f3439c4 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -542,6 +542,8 @@
float right, float bottom, float vecX, float vecY,
float maxAmount);
+ Transaction& setBufferCrop(const sp<SurfaceControl>& sc, const Rect& bufferCrop);
+
status_t setDisplaySurface(const sp<IBinder>& token,
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 8675439..9286009 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -60,7 +60,13 @@
cc_library {
name: "libnativewindow",
- llndk_stubs: "libnativewindow.llndk",
+ llndk: {
+ symbol_file: "libnativewindow.map.txt",
+ unversioned: true,
+ override_export_include_dirs: [
+ "include"
+ ],
+ },
export_include_dirs: [
"include",
"include-private",
@@ -115,11 +121,4 @@
},
}
-llndk_library {
- name: "libnativewindow.llndk",
- symbol_file: "libnativewindow.map.txt",
- unversioned: true,
- export_include_dirs: ["include"],
-}
-
subdirs = ["tests"]
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 61b3f94..3865ba5 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -302,6 +302,8 @@
*
* Available since API level 31.
*
+ * \param window pointer to an ANativeWindow object.
+ *
* \param frameRate The intended frame rate of this window, in frames per
* second. 0 is a special value that indicates the app will accept the system's
* choice for the display frame rate, which is the default behavior if this
@@ -309,15 +311,16 @@
* valid refresh rate for this device's display - e.g., it's fine to pass 30fps
* to a device that can only run the display at 60fps.
*
- * \param window pointer to an ANativeWindow object.
- *
* \param compatibility The frame rate compatibility of this window. The
* compatibility value may influence the system's choice of display refresh
* rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info.
+ * This parameter is ignored when frameRate is 0.
*
- * \param changeFrameRateStrategy Whether display refresh rate transitions should be seamless.
+ * \param changeFrameRateStrategy Whether display refresh rate transitions caused by this
+ * window should be seamless.
* A seamless transition is one that doesn't have any visual interruptions, such as a black
* screen for a second or two. See the ANATIVEWINDOW_CHANGE_FRAME_RATE_* values.
+ * This parameter is ignored when frameRate is 0.
*
* \return 0 for success, -EINVAL if the window, frame rate, or compatibility
* value are invalid.
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index c54c5ba..e976a5a 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -156,6 +156,10 @@
std::vector<BlurRegion> blurRegions;
+ // Transform matrix used to convert the blurRegions geometry into the same
+ // coordinate space as LayerSettings.geometry
+ mat4 blurRegionTransform = mat4();
+
StretchEffect stretchEffect;
// Name associated with the layer for debugging purposes.
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 1c2b2fc..a0da888 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -37,12 +37,17 @@
0.f, 0.7f, 0.f, 0.f,
0.f, 0.f, 1.f, 0.f,
67.3f, 52.2f, 0.f, 1.f);
+const auto kScaleYOnly = mat4(1.f, 0.f, 0.f, 0.f,
+ 0.f, 0.7f, 0.f, 0.f,
+ 0.f, 0.f, 1.f, 0.f,
+ 0.f, 0.f, 0.f, 1.f);
// clang-format on
// When choosing dataspaces below, whether the match the destination or not determined whether
// a color correction effect is added to the shader. There may be other additional shader details
// for particular color spaces.
// TODO(b/184842383) figure out which color related shaders are necessary
constexpr auto kDestDataSpace = ui::Dataspace::SRGB;
+constexpr auto kOtherDataSpace = ui::Dataspace::DISPLAY_P3;
} // namespace
static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
@@ -182,6 +187,37 @@
}
}
+static void drawTextureScaleLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display,
+ const std::shared_ptr<ExternalTexture>& dstTexture,
+ const std::shared_ptr<ExternalTexture>& srcTexture) {
+ const Rect& displayRect = display.physicalDisplay;
+ FloatRect rect(0, 0, displayRect.width(), displayRect.height());
+ LayerSettings layer{
+ .geometry =
+ Geometry{
+ .boundaries = rect,
+ .roundedCornersCrop = rect,
+ .positionTransform = kScaleAndTranslate,
+ .roundedCornersRadius = 300,
+ },
+ .source = PixelSource{.buffer =
+ Buffer{
+ .buffer = srcTexture,
+ .maxMasteringLuminance = 1000.f,
+ .maxContentLuminance = 1000.f,
+ .textureTransform = kScaleYOnly,
+ }},
+ .sourceDataspace = kOtherDataSpace,
+ };
+
+ auto layers = std::vector<const LayerSettings*>{&layer};
+ for (float alpha : {0.5f, 1.f}) {
+ layer.alpha = alpha,
+ renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache,
+ base::unique_fd(), nullptr);
+ }
+}
+
//
// The collection of shaders cached here were found by using perfetto to record shader compiles
// during actions that involve RenderEngine, logging the layer settings, and the shader code
@@ -250,6 +286,9 @@
// between 6 and 8 will occur in real uses.
drawImageLayers(renderengine, display, dstTexture, externalTexture);
+ // Draw layers for b/185569240.
+ drawTextureScaleLayers(renderengine, display, dstTexture, externalTexture);
+
const nsecs_t timeAfter = systemTime();
const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
const int shadersCompiled = renderengine->reportShadersCompiled();
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 377b6f8..acdb78a 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -834,6 +834,8 @@
mBlurFilter->drawBlurRegion(canvas, getBlurRegion(layer), blurRect,
blurredImage, blurInput);
}
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->concat(getSkM44(layer->blurRegionTransform).asM33());
for (auto region : layer->blurRegions) {
if (cachedBlurs[region.blurRadius] == nullptr) {
ATRACE_NAME("BlurRegion");
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 6dd4161..2028def 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -53,7 +53,7 @@
}
)");
- auto [blurEffect, error] = SkRuntimeEffect::Make(blurString);
+ auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString);
if (!blurEffect) {
LOG_ALWAYS_FATAL("RuntimeShader error: %s", error.c_str());
}
@@ -65,11 +65,11 @@
uniform float mixFactor;
half4 main(float2 xy) {
- return half4(mix(sample(originalInput), sample(blurredInput), mixFactor));
+ return half4(mix(sample(originalInput, xy), sample(blurredInput, xy), mixFactor));
}
)");
- auto [mixEffect, mixError] = SkRuntimeEffect::Make(mixString);
+ auto [mixEffect, mixError] = SkRuntimeEffect::MakeForShader(mixString);
if (!mixEffect) {
LOG_ALWAYS_FATAL("RuntimeShader error: %s", mixError.c_str());
}
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index 8e8e42e..0fbd669 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -438,7 +438,7 @@
generateOETF(linearEffect.outputDataspace, shaderString);
generateEffectiveOOTF(linearEffect.undoPremultipliedAlpha, shaderString);
- auto [shader, error] = SkRuntimeEffect::Make(shaderString);
+ auto [shader, error] = SkRuntimeEffect::MakeForShader(shaderString);
if (!shader) {
LOG_ALWAYS_FATAL("LinearColorFilter construction error: %s", error.c_str());
}
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 3878cb1..b15694b 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -69,11 +69,9 @@
host_supported: true,
vendor_available: true,
export_include_dirs: ["include"],
-}
-
-llndk_headers {
- name: "gl_llndk_headers",
- export_include_dirs: ["include"],
+ llndk: {
+ llndk_headers: true,
+ },
}
subdirs = [
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 7861d62..c9fce8a 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -137,7 +137,12 @@
cc_library_shared {
name: "libEGL",
defaults: ["egl_libs_defaults"],
- llndk_stubs: "libEGL.llndk",
+ llndk: {
+ symbol_file: "libEGL.map.txt",
+ export_llndk_headers: ["gl_headers"],
+ // Don't export EGL/include from the LLNDK variant.
+ override_export_include_dirs: [],
+ },
srcs: [
"EGL/egl_tls.cpp",
"EGL/egl_cache.cpp",
@@ -203,7 +208,12 @@
cc_library_shared {
name: "libGLESv1_CM",
defaults: ["gles_libs_defaults"],
- llndk_stubs: "libGLESv1_CM.llndk",
+ llndk: {
+ symbol_file: "libGLESv1_CM.map.txt",
+ export_llndk_headers: ["gl_headers"],
+ // Don't export EGL/include from the LLNDK variant.
+ override_export_include_dirs: [],
+ },
srcs: ["GLES_CM/gl.cpp"],
cflags: ["-DLOG_TAG=\"libGLESv1\""],
version_script: "libGLESv1_CM.map.txt",
@@ -215,7 +225,12 @@
cc_library_shared {
name: "libGLESv2",
defaults: ["gles_libs_defaults"],
- llndk_stubs: "libGLESv2.llndk",
+ llndk: {
+ symbol_file: "libGLESv2.map.txt",
+ export_llndk_headers: ["gl_headers"],
+ // Don't export EGL/include from the LLNDK variant.
+ override_export_include_dirs: [],
+ },
srcs: ["GLES2/gl2.cpp"],
cflags: ["-DLOG_TAG=\"libGLESv2\""],
@@ -230,31 +245,12 @@
cc_library_shared {
name: "libGLESv3",
defaults: ["gles_libs_defaults"],
- llndk_stubs: "libGLESv3.llndk",
+ llndk: {
+ symbol_file: "libGLESv3.map.txt",
+ export_llndk_headers: ["gl_headers"],
+ // Don't export EGL/include from the LLNDK variant.
+ override_export_include_dirs: [],
+ },
srcs: ["GLES2/gl2.cpp"],
cflags: ["-DLOG_TAG=\"libGLESv3\""],
}
-
-llndk_library {
- name: "libEGL.llndk",
- symbol_file: "libEGL.map.txt",
- export_llndk_headers: ["gl_llndk_headers"],
-}
-
-llndk_library {
- name: "libGLESv1_CM.llndk",
- symbol_file: "libGLESv1_CM.map.txt",
- export_llndk_headers: ["gl_llndk_headers"],
-}
-
-llndk_library {
- name: "libGLESv2.llndk",
- symbol_file: "libGLESv2.map.txt",
- export_llndk_headers: ["gl_llndk_headers"],
-}
-
-llndk_library {
- name: "libGLESv3.llndk",
- symbol_file: "libGLESv3.map.txt",
- export_llndk_headers: ["gl_llndk_headers"],
-}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index edbf21a..27443b0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2967,7 +2967,7 @@
return; // Not a key or a motion
}
- std::unordered_set<sp<IBinder>, IBinderHash> newConnectionTokens;
+ std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> newConnectionTokens;
std::vector<sp<Connection>> newConnections;
for (const InputTarget& target : targets) {
if ((target.flags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) ==
@@ -4284,12 +4284,8 @@
return nullptr;
}
-sp<InputWindowHandle> InputDispatcher::getFocusedWindowHandleLocked(int displayId) const {
- sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(displayId);
- return getWindowHandleLocked(focusedToken, displayId);
-}
-
-bool InputDispatcher::hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const {
+sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
+ const sp<InputWindowHandle>& windowHandle) const {
for (auto& it : mWindowHandlesByDisplay) {
const std::vector<sp<InputWindowHandle>>& windowHandles = it.second;
for (const sp<InputWindowHandle>& handle : windowHandles) {
@@ -4301,11 +4297,16 @@
windowHandle->getName().c_str(), it.first,
windowHandle->getInfo()->displayId);
}
- return true;
+ return handle;
}
}
}
- return false;
+ return nullptr;
+}
+
+sp<InputWindowHandle> InputDispatcher::getFocusedWindowHandleLocked(int displayId) const {
+ sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(displayId);
+ return getWindowHandleLocked(focusedToken, displayId);
}
bool InputDispatcher::hasResponsiveConnectionLocked(InputWindowHandle& windowHandle) const {
@@ -4461,7 +4462,7 @@
TouchState& state = stateIt->second;
for (size_t i = 0; i < state.windows.size();) {
TouchedWindow& touchedWindow = state.windows[i];
- if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
+ if (getWindowHandleLocked(touchedWindow.windowHandle) == nullptr) {
if (DEBUG_FOCUS) {
ALOGD("Touched window was removed: %s in display %" PRId32,
touchedWindow.windowHandle->getName().c_str(), displayId);
@@ -4493,7 +4494,7 @@
// Otherwise, they might stick around until the window handle is destroyed
// which might not happen until the next GC.
for (const sp<InputWindowHandle>& oldWindowHandle : oldWindowHandles) {
- if (!hasWindowHandleLocked(oldWindowHandle)) {
+ if (getWindowHandleLocked(oldWindowHandle) == nullptr) {
if (DEBUG_FOCUS) {
ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 5708fac..7ab4fd7 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -221,12 +221,11 @@
void removeConnectionLocked(const sp<Connection>& connection) REQUIRES(mLock);
- struct IBinderHash {
- std::size_t operator()(const sp<IBinder>& b) const {
- return std::hash<IBinder*>{}(b.get());
- }
+ template <typename T>
+ struct StrongPointerHash {
+ std::size_t operator()(const sp<T>& b) const { return std::hash<T*>{}(b.get()); }
};
- std::unordered_map<sp<IBinder>, std::shared_ptr<InputChannel>, IBinderHash>
+ std::unordered_map<sp<IBinder>, std::shared_ptr<InputChannel>, StrongPointerHash<IBinder>>
mInputChannelsByToken GUARDED_BY(mLock);
// Finds the display ID of the gesture monitor identified by the provided token.
@@ -327,10 +326,11 @@
// to loop through all displays.
sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken,
int displayId) const REQUIRES(mLock);
+ sp<InputWindowHandle> getWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const
+ REQUIRES(mLock);
std::shared_ptr<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const
REQUIRES(mLock);
sp<InputWindowHandle> getFocusedWindowHandleLocked(int displayId) const REQUIRES(mLock);
- bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
bool hasResponsiveConnectionLocked(InputWindowHandle& windowHandle) const REQUIRES(mLock);
/*
@@ -371,7 +371,8 @@
std::string mLastAnrState GUARDED_BY(mLock);
// The connection tokens of the channels that the user last interacted, for debugging
- std::unordered_set<sp<IBinder>, IBinderHash> mInteractionConnectionTokens GUARDED_BY(mLock);
+ std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> mInteractionConnectionTokens
+ GUARDED_BY(mLock);
void updateInteractionTokensLocked(const EventEntry& entry,
const std::vector<InputTarget>& targets) REQUIRES(mLock);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 7a5b20d..24b3599 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -284,6 +284,17 @@
return true;
}
+bool BufferStateLayer::setBufferCrop(const Rect& bufferCrop) {
+ if (mCurrentState.bufferCrop == bufferCrop) return false;
+
+ mCurrentState.sequence++;
+ mCurrentState.bufferCrop = bufferCrop;
+
+ mCurrentState.modified = true;
+ setTransactionFlags(eTransactionNeeded);
+ return true;
+}
+
bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix,
bool allowNonRectPreservingTransforms) {
if (mCurrentState.transform.dsdx() == matrix.dsdx &&
@@ -809,10 +820,15 @@
}
Rect BufferStateLayer::computeBufferCrop(const State& s) {
- if (s.buffer) {
+ if (s.buffer && !s.bufferCrop.isEmpty()) {
+ Rect bufferCrop;
+ s.buffer->getBuffer()->getBounds().intersect(s.bufferCrop, &bufferCrop);
+ return bufferCrop;
+ } else if (s.buffer) {
return s.buffer->getBuffer()->getBounds();
+ } else {
+ return s.bufferCrop;
}
- return Rect::INVALID_RECT;
}
sp<Layer> BufferStateLayer::createClone() {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index af4fcae..570a41a 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -88,6 +88,8 @@
FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
void setAutoRefresh(bool autoRefresh) override;
+ bool setBufferCrop(const Rect& bufferCrop) override;
+
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/Clock.h b/services/surfaceflinger/Clock.h
new file mode 100644
index 0000000..3f23c6d
--- /dev/null
+++ b/services/surfaceflinger/Clock.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2021 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 <chrono>
+
+namespace android {
+
+// Abstract interface for timekeeping which can be injected for unit tests.
+class Clock {
+public:
+ Clock() = default;
+ virtual ~Clock() = default;
+
+ // Returns the current time
+ virtual std::chrono::steady_clock::time_point now() const = 0;
+};
+
+class SteadyClock : public Clock {
+public:
+ virtual ~SteadyClock() = default;
+
+ std::chrono::steady_clock::time_point now() const override {
+ return std::chrono::steady_clock::now();
+ }
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
index 7ca91d8..58bb41a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
@@ -96,6 +96,11 @@
// physical translation and finally rotate to the physical orientation.
return rotationTransform * destTranslation * scale * sourceTranslation;
}
+
+ bool operator==(const ProjectionSpace& other) const {
+ return bounds == other.bounds && content == other.content &&
+ orientation == other.orientation;
+ }
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index b31e89e..4cf83d9 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -158,8 +158,12 @@
const ui::Dataspace& outputDataspace = outputState.dataspace;
const ui::Transform::RotationFlags orientation =
ui::Transform::toRotationFlags(outputState.framebufferSpace.orientation);
+
renderengine::DisplaySettings displaySettings{
- .physicalDisplay = Rect(0, 0, mBounds.getWidth(), mBounds.getHeight()),
+ .physicalDisplay = Rect(-mBounds.left + outputState.framebufferSpace.content.left,
+ -mBounds.top + outputState.framebufferSpace.content.top,
+ -mBounds.left + outputState.framebufferSpace.content.right,
+ -mBounds.top + outputState.framebufferSpace.content.bottom),
.clip = viewport,
.outputDataspace = outputDataspace,
.orientation = orientation,
@@ -246,9 +250,7 @@
if (result == NO_ERROR) {
mDrawFence = new Fence(drawFence.release());
- mOutputSpace = ProjectionSpace(ui::Size(outputState.framebufferSpace.bounds.getWidth(),
- outputState.framebufferSpace.bounds.getHeight()),
- mBounds);
+ mOutputSpace = outputState.framebufferSpace;
mTexture = std::move(texture);
mOutputSpace.orientation = outputState.framebufferSpace.orientation;
mOutputDataspace = outputDataspace;
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index 283c692..8884711 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -287,10 +287,11 @@
}
TEST_F(CachedSetTest, render) {
- CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get();
- sp<mock::LayerFE> layerFE1 = mTestLayers[0]->layerFE;
- CachedSet::Layer& layer2 = *mTestLayers[1]->cachedSetLayer.get();
- sp<mock::LayerFE> layerFE2 = mTestLayers[1]->layerFE;
+ // Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0)
+ CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE1 = mTestLayers[1]->layerFE;
+ CachedSet::Layer& layer2 = *mTestLayers[2]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE2 = mTestLayers[2]->layerFE;
CachedSet cachedSet(layer1);
cachedSet.append(CachedSet(layer2));
@@ -307,7 +308,7 @@
const std::vector<const renderengine::LayerSettings*>& layers,
const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
base::unique_fd&&, base::unique_fd*) -> size_t {
- EXPECT_EQ(Rect(0, 0, 2, 2), displaySettings.physicalDisplay);
+ EXPECT_EQ(Rect(-1, -1, 9, 4), displaySettings.physicalDisplay);
EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
displaySettings.orientation);
@@ -324,10 +325,55 @@
cachedSet.render(mRenderEngine, mOutputState);
expectReadyBuffer(cachedSet);
- EXPECT_EQ(Rect(0, 0, 2, 2), cachedSet.getOutputSpace().content);
- EXPECT_EQ(Rect(mOutputState.framebufferSpace.bounds.getWidth(),
- mOutputState.framebufferSpace.bounds.getHeight()),
- cachedSet.getOutputSpace().bounds);
+ EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
+
+ // Now check that appending a new cached set properly cleans up RenderEngine resources.
+ CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
+ cachedSet.append(CachedSet(layer3));
+}
+
+TEST_F(CachedSetTest, rendersWithOffsetFramebufferContent) {
+ // Skip the 0th layer to ensure that the bounding box of the layers is offset from (0, 0)
+ CachedSet::Layer& layer1 = *mTestLayers[1]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE1 = mTestLayers[1]->layerFE;
+ CachedSet::Layer& layer2 = *mTestLayers[2]->cachedSetLayer.get();
+ sp<mock::LayerFE> layerFE2 = mTestLayers[2]->layerFE;
+
+ CachedSet cachedSet(layer1);
+ cachedSet.append(CachedSet(layer2));
+
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompList1;
+ clientCompList1.push_back({});
+ clientCompList1[0].alpha = 0.5f;
+
+ std::vector<compositionengine::LayerFE::LayerSettings> clientCompList2;
+ clientCompList2.push_back({});
+ clientCompList2[0].alpha = 0.75f;
+
+ mOutputState.framebufferSpace = ProjectionSpace(ui::Size(10, 20), Rect(2, 3, 10, 5));
+
+ const auto drawLayers = [&](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>& layers,
+ const std::shared_ptr<renderengine::ExternalTexture>&, const bool,
+ base::unique_fd&&, base::unique_fd*) -> size_t {
+ EXPECT_EQ(Rect(1, 2, 9, 4), displaySettings.physicalDisplay);
+ EXPECT_EQ(mOutputState.layerStackSpace.content, displaySettings.clip);
+ EXPECT_EQ(ui::Transform::toRotationFlags(mOutputState.framebufferSpace.orientation),
+ displaySettings.orientation);
+ EXPECT_EQ(0.5f, layers[0]->alpha);
+ EXPECT_EQ(0.75f, layers[1]->alpha);
+ EXPECT_EQ(ui::Dataspace::SRGB, displaySettings.outputDataspace);
+
+ return NO_ERROR;
+ };
+
+ EXPECT_CALL(*layerFE1, prepareClientCompositionList(_)).WillOnce(Return(clientCompList1));
+ EXPECT_CALL(*layerFE2, prepareClientCompositionList(_)).WillOnce(Return(clientCompList2));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _, _)).WillOnce(Invoke(drawLayers));
+ cachedSet.render(mRenderEngine, mOutputState);
+ expectReadyBuffer(cachedSet);
+
+ EXPECT_EQ(mOutputState.framebufferSpace, cachedSet.getOutputSpace());
// Now check that appending a new cached set properly cleans up RenderEngine resources.
CachedSet::Layer& layer3 = *mTestLayers[2]->cachedSetLayer.get();
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index c528087..373b895 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -275,11 +275,7 @@
mTime += 200ms;
expectAllLayersFlattened(layers);
- EXPECT_EQ(overrideDisplaySpace.bounds,
- Rect(mOutputState.framebufferSpace.bounds.getWidth(),
- mOutputState.framebufferSpace.bounds.getHeight()));
- EXPECT_EQ(overrideDisplaySpace.content, Rect(0, 0, 2, 2));
- EXPECT_EQ(overrideDisplaySpace.orientation, mOutputState.framebufferSpace.orientation);
+ EXPECT_EQ(overrideDisplaySpace, mOutputState.framebufferSpace);
}
TEST_F(FlattenerTest, flattenLayers_FlattenedLayersSetsDamageRegions) {
diff --git a/services/surfaceflinger/FpsReporter.cpp b/services/surfaceflinger/FpsReporter.cpp
index 0bc2d3e..23db805 100644
--- a/services/surfaceflinger/FpsReporter.cpp
+++ b/services/surfaceflinger/FpsReporter.cpp
@@ -26,10 +26,18 @@
namespace android {
-FpsReporter::FpsReporter(frametimeline::FrameTimeline& frameTimeline, SurfaceFlinger& flinger)
- : mFrameTimeline(frameTimeline), mFlinger(flinger) {}
+FpsReporter::FpsReporter(frametimeline::FrameTimeline& frameTimeline, SurfaceFlinger& flinger,
+ std::unique_ptr<Clock> clock)
+ : mFrameTimeline(frameTimeline), mFlinger(flinger), mClock(std::move(clock)) {
+ LOG_ALWAYS_FATAL_IF(mClock == nullptr, "Passed in null clock when constructing FpsReporter!");
+}
-void FpsReporter::dispatchLayerFps() const {
+void FpsReporter::dispatchLayerFps() {
+ const auto now = mClock->now();
+ if (now - mLastDispatch < kMinDispatchDuration) {
+ return;
+ }
+
std::vector<TrackedListener> localListeners;
{
std::scoped_lock lock(mMutex);
@@ -71,6 +79,8 @@
listener.listener->onFpsReported(mFrameTimeline.computeFps(layerIds));
}
+
+ mLastDispatch = now;
}
void FpsReporter::binderDied(const wp<IBinder>& who) {
diff --git a/services/surfaceflinger/FpsReporter.h b/services/surfaceflinger/FpsReporter.h
index 1cec295..bd7b9a5 100644
--- a/services/surfaceflinger/FpsReporter.h
+++ b/services/surfaceflinger/FpsReporter.h
@@ -22,6 +22,7 @@
#include <unordered_map>
+#include "Clock.h"
#include "FrameTimeline/FrameTimeline.h"
namespace android {
@@ -31,12 +32,13 @@
class FpsReporter : public IBinder::DeathRecipient {
public:
- FpsReporter(frametimeline::FrameTimeline& frameTimeline, SurfaceFlinger& flinger);
+ FpsReporter(frametimeline::FrameTimeline& frameTimeline, SurfaceFlinger& flinger,
+ std::unique_ptr<Clock> clock = std::make_unique<SteadyClock>());
// Dispatches updated layer fps values for the registered listeners
// This method promotes Layer weak pointers and performs layer stack traversals, so mStateLock
// must be held when calling this method.
- void dispatchLayerFps() const EXCLUDES(mMutex);
+ void dispatchLayerFps() EXCLUDES(mMutex);
// Override for IBinder::DeathRecipient
void binderDied(const wp<IBinder>&) override;
@@ -61,6 +63,10 @@
frametimeline::FrameTimeline& mFrameTimeline;
SurfaceFlinger& mFlinger;
+ static const constexpr std::chrono::steady_clock::duration kMinDispatchDuration =
+ std::chrono::milliseconds(500);
+ std::unique_ptr<Clock> mClock;
+ std::chrono::steady_clock::time_point mLastDispatch;
std::unordered_map<wp<IBinder>, TrackedListener, WpHash> mListeners GUARDED_BY(mMutex);
};
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index be552c6..0033dbe 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -256,6 +256,10 @@
protoJank |= FrameTimelineEvent::JANK_UNKNOWN;
jankType &= ~JankType::Unknown;
}
+ if (jankType & JankType::SurfaceFlingerStuffing) {
+ protoJank |= FrameTimelineEvent::JANK_SF_STUFFING;
+ jankType &= ~JankType::SurfaceFlingerStuffing;
+ }
// jankType should be 0 if all types of jank were checked for.
LOG_ALWAYS_FATAL_IF(jankType != 0, "Unrecognized jank type value 0x%x", jankType);
@@ -875,7 +879,8 @@
mGpuFence = gpuFence;
}
-void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync) {
+void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync,
+ nsecs_t previousPresentTime) {
if (mPredictionState == PredictionState::Expired ||
mSurfaceFlingerActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
// Cannot do jank classification with expired predictions or invalid signal times. Set the
@@ -949,7 +954,15 @@
mJankType = JankType::Unknown;
}
} else if (mFramePresentMetadata == FramePresentMetadata::LatePresent) {
- if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
+ if (std::abs(mSurfaceFlingerPredictions.presentTime - previousPresentTime) <=
+ mJankClassificationThresholds.presentThreshold ||
+ previousPresentTime > mSurfaceFlingerPredictions.presentTime) {
+ // The previous frame was either presented in the current frame's expected vsync or
+ // it was presented even later than the current frame's expected vsync.
+ mJankType = JankType::SurfaceFlingerStuffing;
+ }
+ if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish &&
+ !(mJankType & JankType::SurfaceFlingerStuffing)) {
// Finish on time, Present late
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
@@ -963,11 +976,12 @@
mJankType = JankType::PredictionError;
}
} else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) {
- if (mFrameStartMetadata == FrameStartMetadata::LateStart) {
- // Late start, Late finish, Late Present
- mJankType = JankType::SurfaceFlingerScheduling;
- } else {
- // OnTime start, Finish late, Present late
+ if (!(mJankType & JankType::SurfaceFlingerStuffing) ||
+ mSurfaceFlingerActuals.presentTime - previousPresentTime >
+ mRefreshRate.getPeriodNsecs() +
+ mJankClassificationThresholds.presentThreshold) {
+ // Classify CPU vs GPU if SF wasn't stuffed or if SF was stuffed but this frame
+ // was presented more than a vsync late.
if (mGpuFence != FenceTime::NO_FENCE &&
mSurfaceFlingerActuals.endTime - mSurfaceFlingerActuals.startTime <
mRefreshRate.getPeriodNsecs()) {
@@ -989,11 +1003,11 @@
}
}
-void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
+void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime, nsecs_t previousPresentTime) {
mSurfaceFlingerActuals.presentTime = signalTime;
nsecs_t deadlineDelta = 0;
nsecs_t deltaToVsync = 0;
- classifyJank(deadlineDelta, deltaToVsync);
+ classifyJank(deadlineDelta, deltaToVsync, previousPresentTime);
for (auto& surfaceFrame : mSurfaceFrames) {
surfaceFrame->onPresent(signalTime, mJankType, mRefreshRate, deadlineDelta, deltaToVsync);
@@ -1158,8 +1172,9 @@
}
}
auto& displayFrame = pendingPresentFence.second;
- displayFrame->onPresent(signalTime);
+ displayFrame->onPresent(signalTime, mPreviousPresentTime);
displayFrame->trace(mSurfaceFlingerPid);
+ mPreviousPresentTime = signalTime;
mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i));
--i;
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 41f4978..0563a53 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -370,7 +370,7 @@
void onSfWakeUp(int64_t token, Fps refreshRate, std::optional<TimelineItem> predictions,
nsecs_t wakeUpTime);
// Sets the appropriate metadata and classifies the jank.
- void onPresent(nsecs_t signalTime);
+ void onPresent(nsecs_t signalTime, nsecs_t previousPresentTime);
// Adds the provided SurfaceFrame to the current display frame.
void addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame);
@@ -398,7 +398,8 @@
void dump(std::string& result, nsecs_t baseTime) const;
void tracePredictions(pid_t surfaceFlingerPid) const;
void traceActuals(pid_t surfaceFlingerPid) const;
- void classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync);
+ void classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync,
+ nsecs_t previousPresentTime);
int64_t mToken = FrameTimelineInfo::INVALID_VSYNC_ID;
@@ -480,6 +481,7 @@
uint32_t mMaxDisplayFrames;
std::shared_ptr<TimeStats> mTimeStats;
const pid_t mSurfaceFlingerPid;
+ nsecs_t mPreviousPresentTime = 0;
const JankClassificationThresholds mJankClassificationThresholds;
static constexpr uint32_t kDefaultMaxDisplayFrames = 64;
// The initial container size for the vector<SurfaceFrames> inside display frame. Although
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 4461420..7707aaf 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -632,6 +632,8 @@
if (!targetSettings.disableBlurs) {
layerSettings.backgroundBlurRadius = getBackgroundBlurRadius();
layerSettings.blurRegions = getBlurRegions();
+ layerSettings.blurRegionTransform =
+ getActiveTransform(getDrawingState()).inverse().asMatrix4();
}
layerSettings.stretchEffect = getDrawingState().stretchEffect;
// Record the name of the layer for debugging further down the stack.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 688a2c3..a83408b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -274,6 +274,8 @@
// Stretch effect to apply to this layer
StretchEffect stretchEffect;
+
+ Rect bufferCrop;
};
/*
@@ -885,6 +887,7 @@
bool setStretchEffect(const StretchEffect& effect);
StretchEffect getStretchEffect() const;
+ virtual bool setBufferCrop(const Rect& /* bufferCrop */) { return false; }
virtual std::atomic<int32_t>* getPendingBufferCounter() { return nullptr; }
virtual std::string getPendingBufferCounterName() { return ""; }
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
index d659398..16f041a 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -15,7 +15,6 @@
*/
#include "OneShotTimer.h"
-
#include <utils/Log.h>
#include <utils/Timers.h>
#include <chrono>
@@ -40,14 +39,9 @@
namespace android {
namespace scheduler {
-std::chrono::steady_clock::time_point OneShotTimer::Clock::now() const {
- return std::chrono::steady_clock::now();
-}
-
OneShotTimer::OneShotTimer(std::string name, const Interval& interval,
const ResetCallback& resetCallback,
- const TimeoutCallback& timeoutCallback,
- std::unique_ptr<OneShotTimer::Clock> clock)
+ const TimeoutCallback& timeoutCallback, std::unique_ptr<Clock> clock)
: mClock(std::move(clock)),
mName(std::move(name)),
mInterval(interval),
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h
index 7285427..09265bb 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.h
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.h
@@ -20,6 +20,7 @@
#include <chrono>
#include <condition_variable>
#include <thread>
+#include "../Clock.h"
#include <android-base/thread_annotations.h>
@@ -36,17 +37,9 @@
using ResetCallback = std::function<void()>;
using TimeoutCallback = std::function<void()>;
- class Clock {
- public:
- Clock() = default;
- virtual ~Clock() = default;
-
- virtual std::chrono::steady_clock::time_point now() const;
- };
-
OneShotTimer(std::string name, const Interval& interval, const ResetCallback& resetCallback,
const TimeoutCallback& timeoutCallback,
- std::unique_ptr<OneShotTimer::Clock> = std::make_unique<OneShotTimer::Clock>());
+ std::unique_ptr<Clock> clock = std::make_unique<SteadyClock>());
~OneShotTimer();
// Initializes and turns on the idle timer.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 57bd045..fac2c65 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -583,13 +583,9 @@
scheduler::LayerHistory::LayerVoteType voteType;
- if (layer->getWindowType() == InputWindowInfo::Type::STATUS_BAR) {
+ if (!mOptions.useContentDetection ||
+ layer->getWindowType() == InputWindowInfo::Type::STATUS_BAR) {
voteType = scheduler::LayerHistory::LayerVoteType::NoVote;
- } else if (!mOptions.useContentDetection) {
- // If the content detection feature is off, all layers are registered at Max. We still keep
- // the layer history, since we use it for other features (like Frame Rate API), so layers
- // still need to be registered.
- voteType = scheduler::LayerHistory::LayerVoteType::Max;
} else if (layer->getWindowType() == InputWindowInfo::Type::WALLPAPER) {
// Running Wallpaper at Min is considered as part of content detection.
voteType = scheduler::LayerHistory::LayerVoteType::Min;
@@ -597,6 +593,9 @@
voteType = scheduler::LayerHistory::LayerVoteType::Heuristic;
}
+ // If the content detection feature is off, we still keep the layer history,
+ // since we use it for other features (like Frame Rate API), so layers
+ // still need to be registered.
mLayerHistory->registerLayer(layer, voteType);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b048682..2dace92 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4033,6 +4033,11 @@
flags |= eTraversalNeeded;
}
}
+ if (what & layer_state_t::eBufferCropChanged) {
+ if (layer->setBufferCrop(s.bufferCrop)) {
+ flags |= eTraversalNeeded;
+ }
+ }
// This has to happen after we reparent children because when we reparent to null we remove
// child layers from current state and remove its relative z. If the children are reparented in
// the same transaction, then we have to make sure we reparent the children first so we do not
diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
index a2291b2..dec0ff5 100644
--- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
@@ -28,6 +28,7 @@
#include "FpsReporter.h"
#include "Layer.h"
#include "TestableSurfaceFlinger.h"
+#include "fake/FakeClock.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/MockEventThread.h"
#include "mock/MockFrameTimeline.h"
@@ -91,7 +92,9 @@
sp<Layer> mUnrelated;
sp<TestableFpsListener> mFpsListener;
- sp<FpsReporter> mFpsReporter = new FpsReporter(mFrameTimeline, *(mFlinger.flinger()));
+ fake::FakeClock* mClock = new fake::FakeClock();
+ sp<FpsReporter> mFpsReporter =
+ new FpsReporter(mFrameTimeline, *(mFlinger.flinger()), std::unique_ptr<Clock>(mClock));
};
FpsReporterTest::FpsReporterTest() {
@@ -178,6 +181,7 @@
.WillOnce(Return(expectedFps));
mFpsReporter->addListener(mFpsListener, kTaskId);
+ mClock->advanceTime(600ms);
mFpsReporter->dispatchLayerFps();
EXPECT_EQ(expectedFps, mFpsListener->lastReportedFps);
mFpsReporter->removeListener(mFpsListener);
@@ -187,5 +191,34 @@
mFpsReporter->dispatchLayerFps();
}
+TEST_F(FpsReporterTest, rateLimits) {
+ const constexpr int32_t kTaskId = 12;
+ LayerMetadata targetMetadata;
+ targetMetadata.setInt32(METADATA_TASK_ID, kTaskId);
+ mTarget = createBufferStateLayer(targetMetadata);
+ mFlinger.mutableCurrentState().layersSortedByZ.add(mTarget);
+
+ float firstFps = 44.0;
+ float secondFps = 53.0;
+
+ EXPECT_CALL(mFrameTimeline, computeFps(UnorderedElementsAre(mTarget->getSequence())))
+ .WillOnce(Return(firstFps))
+ .WillOnce(Return(secondFps));
+
+ mFpsReporter->addListener(mFpsListener, kTaskId);
+ mClock->advanceTime(600ms);
+ mFpsReporter->dispatchLayerFps();
+ EXPECT_EQ(firstFps, mFpsListener->lastReportedFps);
+ mClock->advanceTime(200ms);
+ mFpsReporter->dispatchLayerFps();
+ EXPECT_EQ(firstFps, mFpsListener->lastReportedFps);
+ mClock->advanceTime(200ms);
+ mFpsReporter->dispatchLayerFps();
+ EXPECT_EQ(firstFps, mFpsListener->lastReportedFps);
+ mClock->advanceTime(200ms);
+ mFpsReporter->dispatchLayerFps();
+ EXPECT_EQ(secondFps, mFpsListener->lastReportedFps);
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 8a3f561..6ed6148 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -1561,13 +1561,22 @@
/*
* Case 1 - cpu time > vsync period but combined time > deadline > deadline -> cpudeadlinemissed
* Case 2 - cpu time < vsync period but combined time > deadline -> gpudeadlinemissed
+ * Case 3 - previous frame ran longer -> sf_stuffing
+ * Case 4 - Long cpu under SF stuffing -> cpudeadlinemissed
*/
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto presentFence3 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto presentFence4 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
auto gpuFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto gpuFence3 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto gpuFence4 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+ int64_t sfToken3 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+ int64_t sfToken4 = mTokenManager->generateTokenForPredictions({112, 120, 120});
+
// case 1 - cpu time = 33 - 12 = 21, vsync period = 11
mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
mFrameTimeline->setSfPresent(33, presentFence1, gpuFence1);
@@ -1578,12 +1587,12 @@
// Fences haven't been flushed yet, so it should be 0
EXPECT_EQ(displayFrame0->getActuals().presentTime, 0);
- // case 2 - cpu time = 56 - 52 = 4, vsync period = 11
- mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
+ // case 2 - cpu time = 56 - 52 = 4, vsync period = 30
+ mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(30));
mFrameTimeline->setSfPresent(56, presentFence2, gpuFence2);
auto displayFrame1 = getDisplayFrame(1);
- gpuFence2->signalForTest(66);
- presentFence2->signalForTest(71);
+ gpuFence2->signalForTest(76);
+ presentFence2->signalForTest(90);
EXPECT_EQ(displayFrame1->getActuals().presentTime, 0);
// Fences have flushed for first displayFrame, so the present timestamps should be updated
@@ -1592,35 +1601,41 @@
EXPECT_EQ(displayFrame0->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(displayFrame0->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
- addEmptyDisplayFrame();
+ // case 3 - cpu time = 86 - 82 = 4, vsync period = 30
+ mFrameTimeline->setSfWakeUp(sfToken3, 106, Fps::fromPeriodNsecs(30));
+ mFrameTimeline->setSfPresent(112, presentFence3, gpuFence3);
+ auto displayFrame2 = getDisplayFrame(2);
+ gpuFence3->signalForTest(116);
+ presentFence3->signalForTest(120);
+ EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
// Fences have flushed for second displayFrame, so the present timestamps should be updated
- EXPECT_EQ(displayFrame1->getActuals().presentTime, 71);
+ EXPECT_EQ(displayFrame1->getActuals().presentTime, 90);
EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
EXPECT_EQ(displayFrame1->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed);
-}
-TEST_F(FrameTimelineTest, jankClassification_displayFrameLateStartLateFinishLatePresent) {
- auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
- mFrameTimeline->setSfWakeUp(sfToken1, 26, Fps::fromPeriodNsecs(11));
- mFrameTimeline->setSfPresent(36, presentFence1);
- auto displayFrame = getDisplayFrame(0);
- presentFence1->signalForTest(52);
+ // case 4 - cpu time = 86 - 82 = 4, vsync period = 30
+ mFrameTimeline->setSfWakeUp(sfToken4, 120, Fps::fromPeriodNsecs(30));
+ mFrameTimeline->setSfPresent(140, presentFence4, gpuFence4);
+ auto displayFrame3 = getDisplayFrame(3);
+ gpuFence4->signalForTest(156);
+ presentFence4->signalForTest(180);
- // Fences haven't been flushed yet, so it should be 0
- EXPECT_EQ(displayFrame->getActuals().presentTime, 0);
+ EXPECT_EQ(displayFrame3->getActuals().presentTime, 0);
+ // Fences have flushed for third displayFrame, so the present timestamps should be updated
+ EXPECT_EQ(displayFrame2->getActuals().presentTime, 120);
+ EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+ EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+ EXPECT_EQ(displayFrame2->getJankType(), JankType::SurfaceFlingerStuffing);
addEmptyDisplayFrame();
- displayFrame = getDisplayFrame(0);
- // Fences have flushed, so the present timestamps should be updated
- EXPECT_EQ(displayFrame->getActuals().presentTime, 52);
- EXPECT_EQ(displayFrame->getFrameStartMetadata(), FrameStartMetadata::LateStart);
- EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
- EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
- EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerScheduling);
+ // Fences have flushed for third displayFrame, so the present timestamps should be updated
+ EXPECT_EQ(displayFrame3->getActuals().presentTime, 180);
+ EXPECT_EQ(displayFrame3->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+ EXPECT_EQ(displayFrame3->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+ EXPECT_EQ(displayFrame3->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed);
}
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresent) {
diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index a1f0588..6916764 100644
--- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -23,23 +23,13 @@
#include "AsyncCallRecorder.h"
#include "Scheduler/OneShotTimer.h"
+#include "fake/FakeClock.h"
using namespace std::chrono_literals;
namespace android {
namespace scheduler {
-class FakeClock : public OneShotTimer::Clock {
-public:
- virtual ~FakeClock() = default;
- std::chrono::steady_clock::time_point now() const override { return mNow; }
-
- void advanceTime(std::chrono::nanoseconds delta) { mNow += delta; }
-
-private:
- std::chrono::steady_clock::time_point mNow;
-};
-
class OneShotTimerTest : public testing::Test {
protected:
OneShotTimerTest() = default;
@@ -58,17 +48,17 @@
namespace {
TEST_F(OneShotTimerTest, createAndDestroyTest) {
- FakeClock* clock = new FakeClock();
+ fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
- "TestTimer", 3ms, [] {}, [] {}, std::unique_ptr<FakeClock>(clock));
+ "TestTimer", 3ms, [] {}, [] {}, std::unique_ptr<fake::FakeClock>(clock));
}
TEST_F(OneShotTimerTest, startStopTest) {
- FakeClock* clock = new FakeClock();
+ fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable(),
- std::unique_ptr<FakeClock>(clock));
+ std::unique_ptr<fake::FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
@@ -83,11 +73,11 @@
}
TEST_F(OneShotTimerTest, resetTest) {
- FakeClock* clock = new FakeClock();
+ fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable(),
- std::unique_ptr<FakeClock>(clock));
+ std::unique_ptr<fake::FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -105,11 +95,11 @@
}
TEST_F(OneShotTimerTest, resetBackToBackTest) {
- FakeClock* clock = new FakeClock();
+ fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable(),
- std::unique_ptr<FakeClock>(clock));
+ std::unique_ptr<fake::FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -139,11 +129,11 @@
}
TEST_F(OneShotTimerTest, startNotCalledTest) {
- FakeClock* clock = new FakeClock();
+ fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable(),
- std::unique_ptr<FakeClock>(clock));
+ std::unique_ptr<fake::FakeClock>(clock));
// The start hasn't happened, so the callback does not happen.
EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
@@ -155,11 +145,11 @@
}
TEST_F(OneShotTimerTest, idleTimerIdlesTest) {
- FakeClock* clock = new FakeClock();
+ fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable(),
- std::unique_ptr<FakeClock>(clock));
+ std::unique_ptr<fake::FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
clock->advanceTime(2ms);
@@ -180,11 +170,11 @@
}
TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) {
- FakeClock* clock = new FakeClock();
+ fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable(),
- std::unique_ptr<FakeClock>(clock));
+ std::unique_ptr<fake::FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -197,11 +187,11 @@
}
TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) {
- FakeClock* clock = new FakeClock();
+ fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable(),
- std::unique_ptr<FakeClock>(clock));
+ std::unique_ptr<fake::FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
clock->advanceTime(2ms);
@@ -215,11 +205,11 @@
}
TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) {
- FakeClock* clock = new FakeClock();
+ fake::FakeClock* clock = new fake::FakeClock();
mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
mResetTimerCallback.getInvocable(),
mExpiredTimerCallback.getInvocable(),
- std::unique_ptr<FakeClock>(clock));
+ std::unique_ptr<fake::FakeClock>(clock));
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
EXPECT_FALSE(mExpiredTimerCallback.waitForUnexpectedCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/fake/FakeClock.h b/services/surfaceflinger/tests/unittests/fake/FakeClock.h
new file mode 100644
index 0000000..6d9c764
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/fake/FakeClock.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 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 "../../Clock.h"
+
+namespace android::fake {
+
+class FakeClock : public Clock {
+public:
+ virtual ~FakeClock() = default;
+ std::chrono::steady_clock::time_point now() const override { return mNow; }
+
+ void advanceTime(std::chrono::nanoseconds delta) { mNow += delta; }
+
+private:
+ std::chrono::steady_clock::time_point mNow;
+};
+
+} // namespace android::fake
\ No newline at end of file
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 67cd875..440c5b1 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -29,17 +29,14 @@
unversioned_until: "current",
}
-llndk_library {
- name: "libvulkan.llndk",
- symbol_file: "libvulkan.map.txt",
- export_llndk_headers: [
- "vulkan_headers_llndk",
- ],
-}
-
cc_library_shared {
name: "libvulkan",
- llndk_stubs: "libvulkan.llndk",
+ llndk: {
+ symbol_file: "libvulkan.map.txt",
+ export_llndk_headers: [
+ "vulkan_headers",
+ ],
+ },
clang: true,
sanitize: {
misc_undefined: ["integer"],