Merge "Revert "Check for adpf cpu hints for SurfaceFlinger during init""
diff --git a/Android.bp b/Android.bp
index dec6716..615a7a8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -64,14 +64,20 @@
name: "framework_native_aidl_binder",
srcs: ["aidl/binder/**/*.aidl"],
path: "aidl/binder",
- visibility: ["//frameworks/native"],
+ visibility: [
+ "//frameworks/native",
+ "//frameworks/native/libs/gui",
+ ],
}
filegroup {
name: "framework_native_aidl_gui",
srcs: ["aidl/gui/**/*.aidl"],
path: "aidl/gui",
- visibility: ["//frameworks/native"],
+ visibility: [
+ "//frameworks/native",
+ "//frameworks/native/libs/gui",
+ ],
}
filegroup {
@@ -82,7 +88,7 @@
],
}
-cc_library_headers{
+cc_library_headers {
name: "libandroid_headers_private",
export_include_dirs: ["include/private"],
}
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 6d837c2..3480d63 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,8 +1,10 @@
[Builtin Hooks]
+rustfmt = true
bpfmt = true
clang_format = true
[Builtin Hooks Options]
+rustfmt = --config-path=rustfmt.toml
# Only turn on clang-format check for the following subfolders.
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
cmds/idlcli/
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 891b1c6..2e0c95a 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -300,6 +300,12 @@
chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger
chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
+on late-init && property:ro.boot.fastboot.boottrace=enabled
+ setprop debug.atrace.tags.enableflags 802922
+ setprop persist.traced.enable 0
+ write /sys/kernel/debug/tracing/tracing_on 1
+ write /sys/kernel/tracing/tracing_on 1
+
# Only create the tracing instance if persist.mm_events.enabled
# Attempting to remove the tracing instance after it has been created
# will likely fail with EBUSY as it would be in use by traced_probes.
@@ -395,3 +401,10 @@
service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categories
disabled
oneshot
+
+on property:sys.boot_completed=1 && property:ro.boot.fastboot.boottrace=enabled
+ setprop debug.atrace.tags.enableflags 0
+ setprop persist.traced.enable 1
+ write /sys/kernel/debug/tracing/tracing_on 0
+ write /sys/kernel/tracing/tracing_on 0
+
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
index b7e520f..711038c 100644
--- a/cmds/servicemanager/Access.cpp
+++ b/cmds/servicemanager/Access.cpp
@@ -30,6 +30,7 @@
constexpr bool kIsVendor = false;
#endif
+#ifdef __ANDROID__
static std::string getPidcon(pid_t pid) {
android_errorWriteLog(0x534e4554, "121035042");
@@ -45,7 +46,6 @@
static struct selabel_handle* getSehandle() {
static struct selabel_handle* gSehandle = nullptr;
-
if (gSehandle != nullptr && selinux_status_updated()) {
selabel_close(gSehandle);
gSehandle = nullptr;
@@ -78,8 +78,10 @@
ad->tname->c_str());
return 0;
}
+#endif
Access::Access() {
+#ifdef __ANDROID__
union selinux_callback cb;
cb.func_audit = auditCallback;
@@ -91,6 +93,7 @@
CHECK(selinux_status_open(true /*fallback*/) >= 0);
CHECK(getcon(&mThisProcessContext) == 0);
+#endif
}
Access::~Access() {
@@ -98,6 +101,7 @@
}
Access::CallingContext Access::getCallingContext() {
+#ifdef __ANDROID__
IPCThreadState* ipc = IPCThreadState::self();
const char* callingSid = ipc->getCallingSid();
@@ -108,6 +112,9 @@
.uid = ipc->getCallingUid(),
.sid = callingSid ? std::string(callingSid) : getPidcon(callingPid),
};
+#else
+ return CallingContext();
+#endif
}
bool Access::canFind(const CallingContext& ctx,const std::string& name) {
@@ -124,6 +131,7 @@
bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm,
const std::string& tname) {
+#ifdef __ANDROID__
const char* tclass = "service_manager";
AuditCallbackData data = {
@@ -133,9 +141,18 @@
return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm,
reinterpret_cast<void*>(&data));
+#else
+ (void)sctx;
+ (void)tctx;
+ (void)perm;
+ (void)tname;
+
+ return true;
+#endif
}
bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) {
+#ifdef __ANDROID__
char *tctx = nullptr;
if (selabel_lookup(getSehandle(), &tctx, name.c_str(), SELABEL_CTX_ANDROID_SERVICE) != 0) {
LOG(ERROR) << "SELinux: No match for " << name << " in service_contexts.\n";
@@ -145,6 +162,14 @@
bool allowed = actionAllowed(sctx, tctx, perm, name);
freecon(tctx);
return allowed;
+#else
+ (void)sctx;
+ (void)name;
+ (void)perm;
+ (void)kIsVendor;
+
+ return true;
+#endif
}
} // android
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 3b753c6..25bd9a3 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -87,3 +87,35 @@
],
static_libs: ["libgmock"],
}
+
+cc_fuzz {
+ name: "servicemanager_fuzzer",
+ defaults: ["servicemanager_defaults"],
+ host_supported: true,
+ static_libs: [
+ "libbase",
+ "libbinder_random_parcel",
+ "libcutils",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "libbinder_ndk",
+ "libbinder",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libbinder_ndk",
+ "libbinder",
+ ],
+ },
+ },
+ srcs: ["ServiceManagerFuzzer.cpp"],
+ fuzz_config: {
+ cc: [
+ "smoreland@google.com",
+ "waghpawan@google.com",
+ ],
+ },
+}
diff --git a/cmds/servicemanager/ServiceManagerFuzzer.cpp b/cmds/servicemanager/ServiceManagerFuzzer.cpp
new file mode 100644
index 0000000..9e2e53f
--- /dev/null
+++ b/cmds/servicemanager/ServiceManagerFuzzer.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 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 <fuzzbinder/libbinder_driver.h>
+#include <utils/StrongPointer.h>
+
+#include "Access.h"
+#include "ServiceManager.h"
+
+using ::android::Access;
+using ::android::fuzzService;
+using ::android::ServiceManager;
+using ::android::sp;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size > 50000) {
+ return 0;
+ }
+
+ auto accessPtr = std::make_unique<Access>();
+ auto serviceManager = sp<ServiceManager>::make(std::move(accessPtr));
+ fuzzService(serviceManager, FuzzedDataProvider(data, size));
+
+ return 0;
+}
\ No newline at end of file
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index 1d458b7..a831d1b 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -15,6 +15,7 @@
*/
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/Status.h>
@@ -26,15 +27,14 @@
#include "ServiceManager.h"
using ::android::Access;
-using ::android::sp;
+using ::android::IPCThreadState;
using ::android::Looper;
using ::android::LooperCallback;
using ::android::ProcessState;
-using ::android::IPCThreadState;
-using ::android::ProcessState;
using ::android::ServiceManager;
-using ::android::os::IServiceManager;
using ::android::sp;
+using ::android::base::SetProperty;
+using ::android::os::IServiceManager;
class BinderCallback : public LooperCallback {
public:
@@ -140,6 +140,12 @@
BinderCallback::setupTo(looper);
ClientCallbackCallback::setupTo(looper, manager);
+#ifndef VENDORSERVICEMANAGER
+ if (!SetProperty("servicemanager.ready", "true")) {
+ LOG(ERROR) << "Failed to set servicemanager ready property";
+ }
+#endif
+
while(true) {
looper->pollAll(-1);
}
diff --git a/cmds/servicemanager/servicemanager.microdroid.rc b/cmds/servicemanager/servicemanager.microdroid.rc
index e01f132..c516043 100644
--- a/cmds/servicemanager/servicemanager.microdroid.rc
+++ b/cmds/servicemanager/servicemanager.microdroid.rc
@@ -3,6 +3,7 @@
user system
group system readproc
critical
+ onrestart setprop servicemanager.ready false
onrestart restart apexd
task_profiles ServiceCapacityLow
shutdown critical
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index e5d689f..6b35265 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -3,6 +3,7 @@
user system
group system readproc
critical
+ onrestart setprop servicemanager.ready false
onrestart restart apexd
onrestart restart audioserver
onrestart restart gatekeeperd
diff --git a/cmds/servicemanager/servicemanager.recovery.rc b/cmds/servicemanager/servicemanager.recovery.rc
index 067faf9..b927c01 100644
--- a/cmds/servicemanager/servicemanager.recovery.rc
+++ b/cmds/servicemanager/servicemanager.recovery.rc
@@ -1,4 +1,5 @@
service servicemanager /system/bin/servicemanager
disabled
group system readproc
+ onrestart setprop servicemanager.ready false
seclabel u:r:servicemanager:s0
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index e65b224..4746bc3 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -318,6 +318,9 @@
OMX_VIDEO_DolbyVisionLevelUhd30 = 0x40,
OMX_VIDEO_DolbyVisionLevelUhd48 = 0x80,
OMX_VIDEO_DolbyVisionLevelUhd60 = 0x100,
+ OMX_VIDEO_DolbyVisionLevelUhd120 = 0x200,
+ OMX_VIDEO_DolbyVisionLevel8k30 = 0x400,
+ OMX_VIDEO_DolbyVisionLevel8k60 = 0x800,
OMX_VIDEO_DolbyVisionLevelmax = 0x7FFFFFFF
} OMX_VIDEO_DOLBYVISIONLEVELTYPE;
diff --git a/include/android/input.h b/include/android/input.h
index 38b27bc..8cd9e95 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -54,7 +54,14 @@
#include <stdint.h>
#include <sys/types.h>
#include <android/keycodes.h>
+
+// This file is included by modules that have host support but android/looper.h is not supported
+// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled.
+#ifndef __BIONIC__
+#define __REMOVED_IN(x) __attribute__((deprecated))
+#endif
#include <android/looper.h>
+
#include <jni.h>
#if !defined(__INTRODUCED_IN)
diff --git a/include/android/looper.h b/include/android/looper.h
index 718f703..4fe142a 100644
--- a/include/android/looper.h
+++ b/include/android/looper.h
@@ -201,8 +201,11 @@
* Like ALooper_pollOnce(), but performs all pending callbacks until all
* data has been consumed or a file descriptor is available with no callback.
* This function will never return ALOOPER_POLL_CALLBACK.
+ *
+ * Removed in API 34 as ALooper_pollAll can swallow ALooper_wake calls.
+ * Use ALooper_pollOnce instead.
*/
-int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData);
+int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) __REMOVED_IN(1);
/**
* Wakes the poll asynchronously.
diff --git a/include/android/sensor.h b/include/android/sensor.h
index eef69f4..105f952 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -45,6 +45,11 @@
* - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
*/
+// This file is included by modules that have host support but android/looper.h is not supported
+// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled.
+#ifndef __BIONIC__
+#define __REMOVED_IN(x) __attribute__((deprecated))
+#endif
#include <android/looper.h>
#include <stdbool.h>
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
index caf13a0..6794fbf 100644
--- a/include/audiomanager/AudioManager.h
+++ b/include/audiomanager/AudioManager.h
@@ -39,8 +39,51 @@
PLAYER_STATE_STOPPED = 4,
PLAYER_UPDATE_DEVICE_ID = 5,
PLAYER_UPDATE_PORT_ID = 6,
+ PLAYER_UPDATE_MUTED = 7,
} player_state_t;
+static constexpr char
+ kExtraPlayerEventMuteKey[] = "android.media.extra.PLAYER_EVENT_MUTE";
+enum {
+ PLAYER_MUTE_MASTER = (1 << 0),
+ PLAYER_MUTE_STREAM_VOLUME = (1 << 1),
+ PLAYER_MUTE_STREAM_MUTED = (1 << 2),
+ PLAYER_MUTE_PLAYBACK_RESTRICTED = (1 << 3),
+ PLAYER_MUTE_CLIENT_VOLUME = (1 << 4),
+ PLAYER_MUTE_VOLUME_SHAPER = (1 << 5),
+};
+
+struct mute_state_t {
+ /** Flag used when the master volume is causing the mute state. */
+ bool muteFromMasterMute = false;
+ /** Flag used when the stream volume is causing the mute state. */
+ bool muteFromStreamVolume = false;
+ /** Flag used when the stream muted is causing the mute state. */
+ bool muteFromStreamMuted = false;
+ /** Flag used when playback is restricted by AppOps manager with OP_PLAY_AUDIO. */
+ bool muteFromPlaybackRestricted = false;
+ /** Flag used when audio track was muted by client volume. */
+ bool muteFromClientVolume = false;
+ /** Flag used when volume is muted by volume shaper. */
+ bool muteFromVolumeShaper = false;
+
+ explicit operator int() const
+ {
+ int result = muteFromMasterMute * PLAYER_MUTE_MASTER;
+ result |= muteFromStreamVolume * PLAYER_MUTE_STREAM_VOLUME;
+ result |= muteFromStreamMuted * PLAYER_MUTE_STREAM_MUTED;
+ result |= muteFromPlaybackRestricted * PLAYER_MUTE_PLAYBACK_RESTRICTED;
+ result |= muteFromClientVolume * PLAYER_MUTE_CLIENT_VOLUME;
+ result |= muteFromVolumeShaper * PLAYER_MUTE_VOLUME_SHAPER;
+ return result;
+ }
+
+ bool operator==(const mute_state_t& other) const
+ {
+ return static_cast<int>(*this) == static_cast<int>(other);
+ }
+};
+
// must be kept in sync with definitions in AudioManager.java
#define RECORD_RIID_INVALID -1
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index 3d531fe..769670e 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -20,6 +20,7 @@
#include <audiomanager/AudioManager.h>
#include <utils/Errors.h>
#include <binder/IInterface.h>
+#include <binder/PersistableBundle.h>
#include <hardware/power.h>
#include <system/audio.h>
@@ -41,6 +42,7 @@
RECORDER_EVENT = IBinder::FIRST_CALL_TRANSACTION + 5,
RELEASE_RECORDER = IBinder::FIRST_CALL_TRANSACTION + 6,
PLAYER_SESSION_ID = IBinder::FIRST_CALL_TRANSACTION + 7,
+ PORT_EVENT = IBinder::FIRST_CALL_TRANSACTION + 8,
};
DECLARE_META_INTERFACE(AudioManager)
@@ -59,6 +61,8 @@
/*oneway*/ virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) = 0;
/*oneway*/ virtual status_t releaseRecorder(audio_unique_id_t riid) = 0;
/*oneway*/ virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) = 0;
+ /*oneway*/ virtual status_t portEvent(audio_port_handle_t portId, player_state_t event,
+ const std::unique_ptr<os::PersistableBundle>& extras) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/input/Input.h b/include/input/Input.h
index e0c9de4..a3c9f33 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -297,6 +297,8 @@
*/
const char* motionClassificationToString(MotionClassification classification);
+const char* motionToolTypeToString(int32_t toolType);
+
/**
* Portion of FrameMetrics timeline of interest to input code.
*/
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index f6f8939..1c9a5ea 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -18,6 +18,7 @@
#define _LIBINPUT_KEY_CHARACTER_MAP_H
#include <stdint.h>
+#include <list>
#ifdef __linux__
#include <binder/IBinder.h>
@@ -152,29 +153,22 @@
private:
struct Behavior {
- Behavior();
- Behavior(const Behavior& other);
-
- /* The next behavior in the list, or NULL if none. */
- Behavior* next;
-
/* The meta key modifiers for this behavior. */
- int32_t metaState;
+ int32_t metaState = 0;
/* The character to insert. */
- char16_t character;
+ char16_t character = 0;
/* The fallback keycode if the key is not handled. */
- int32_t fallbackKeyCode;
+ int32_t fallbackKeyCode = 0;
/* The replacement keycode if the key has to be replaced outright. */
- int32_t replacementKeyCode;
+ int32_t replacementKeyCode = 0;
};
struct Key {
Key();
Key(const Key& other);
- ~Key();
/* The single character label printed on the key, or 0 if none. */
char16_t label;
@@ -184,7 +178,7 @@
/* The list of key behaviors sorted from most specific to least specific
* meta key binding. */
- Behavior* firstBehavior;
+ std::list<Behavior> behaviors;
};
class Parser {
@@ -240,8 +234,7 @@
KeyCharacterMap(const std::string& filename);
bool getKey(int32_t keyCode, const Key** outKey) const;
- bool getKeyBehavior(int32_t keyCode, int32_t metaState,
- const Key** outKey, const Behavior** outBehavior) const;
+ const Behavior* getKeyBehavior(int32_t keyCode, int32_t metaState) const;
static bool matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState);
bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 532bacb..b5ea60f 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -610,8 +610,24 @@
BBinder::~BBinder()
{
- if (!wasParceled() && getExtension()) {
- ALOGW("Binder %p destroyed with extension attached before being parceled.", this);
+ if (!wasParceled()) {
+ if (getExtension()) {
+ ALOGW("Binder %p destroyed with extension attached before being parceled.", this);
+ }
+ if (isRequestingSid()) {
+ ALOGW("Binder %p destroyed when requesting SID before being parceled.", this);
+ }
+ if (isInheritRt()) {
+ ALOGW("Binder %p destroyed after setInheritRt before being parceled.", this);
+ }
+#ifdef __linux__
+ if (getMinSchedulerPolicy() != SCHED_NORMAL) {
+ ALOGW("Binder %p destroyed after setMinSchedulerPolicy before being parceled.", this);
+ }
+ if (getMinSchedulerPriority() != 0) {
+ ALOGW("Binder %p destroyed after setMinSchedulerPolicy before being parceled.", this);
+ }
+#endif // __linux__
}
Extras* e = mExtras.load(std::memory_order_relaxed);
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
index 5c7102e..a25dc11 100644
--- a/libs/binder/FdTrigger.h
+++ b/libs/binder/FdTrigger.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#include <memory>
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index fd47783..c0a8d74 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -21,6 +21,7 @@
#include <inttypes.h>
#include <unistd.h>
+#include <android-base/properties.h>
#include <android/os/BnServiceCallback.h>
#include <android/os/IServiceManager.h>
#include <binder/IPCThreadState.h>
@@ -140,6 +141,16 @@
sp<IServiceManager> defaultServiceManager()
{
std::call_once(gSmOnce, []() {
+#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__)
+ /* wait for service manager */ {
+ using std::literals::chrono_literals::operator""s;
+ using android::base::WaitForProperty;
+ while (!WaitForProperty("servicemanager.ready", "true", 1s)) {
+ ALOGE("Waited for servicemanager.ready for a second, waiting another...");
+ }
+ }
+#endif
+
sp<AidlServiceManager> sm = nullptr;
while (sm == nullptr) {
sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index e6dbd79..d347262 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -36,6 +36,7 @@
#include <utils/Compat.h>
#include <utils/String8.h>
+#include "BuildFlags.h"
#include "FdTrigger.h"
#include "OS.h"
#include "RpcSocketAddress.h"
@@ -78,10 +79,8 @@
void RpcSession::setMaxIncomingThreads(size_t threads) {
RpcMutexLockGuard _l(mMutex);
- LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
- "Must set max incoming threads before setting up connections, but has %zu "
- "client(s) and %zu server(s)",
- mConnections.mOutgoing.size(), mConnections.mIncoming.size());
+ LOG_ALWAYS_FATAL_IF(mStartedSetup,
+ "Must set max incoming threads before setting up connections");
mMaxIncomingThreads = threads;
}
@@ -92,10 +91,8 @@
void RpcSession::setMaxOutgoingThreads(size_t threads) {
RpcMutexLockGuard _l(mMutex);
- LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
- "Must set max outgoing threads before setting up connections, but has %zu "
- "client(s) and %zu server(s)",
- mConnections.mOutgoing.size(), mConnections.mIncoming.size());
+ LOG_ALWAYS_FATAL_IF(mStartedSetup,
+ "Must set max outgoing threads before setting up connections");
mMaxOutgoingThreads = threads;
}
@@ -104,7 +101,7 @@
return mMaxOutgoingThreads;
}
-bool RpcSession::setProtocolVersion(uint32_t version) {
+bool RpcSession::setProtocolVersionInternal(uint32_t version, bool checkStarted) {
if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT &&
version != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
ALOGE("Cannot start RPC session with version %u which is unknown (current protocol version "
@@ -114,6 +111,8 @@
}
RpcMutexLockGuard _l(mMutex);
+ LOG_ALWAYS_FATAL_IF(checkStarted && mStartedSetup,
+ "Must set protocol version before setting up connections");
if (mProtocolVersion && version > *mProtocolVersion) {
ALOGE("Cannot upgrade explicitly capped protocol version %u to newer version %u",
*mProtocolVersion, version);
@@ -124,12 +123,19 @@
return true;
}
+bool RpcSession::setProtocolVersion(uint32_t version) {
+ return setProtocolVersionInternal(version, true);
+}
+
std::optional<uint32_t> RpcSession::getProtocolVersion() {
RpcMutexLockGuard _l(mMutex);
return mProtocolVersion;
}
void RpcSession::setFileDescriptorTransportMode(FileDescriptorTransportMode mode) {
+ RpcMutexLockGuard _l(mMutex);
+ LOG_ALWAYS_FATAL_IF(mStartedSetup,
+ "Must set file descriptor transport mode before setting up connections");
mFileDescriptorTransportMode = mode;
}
@@ -445,9 +451,16 @@
bool incoming)>& connectAndInit) {
{
RpcMutexLockGuard _l(mMutex);
- LOG_ALWAYS_FATAL_IF(mConnections.mOutgoing.size() != 0,
- "Must only setup session once, but already has %zu clients",
- mConnections.mOutgoing.size());
+ LOG_ALWAYS_FATAL_IF(mStartedSetup, "Must only setup session once");
+ mStartedSetup = true;
+
+ if constexpr (!kEnableRpcThreads) {
+ LOG_ALWAYS_FATAL_IF(mMaxIncomingThreads > 0,
+ "Incoming threads are not supported on single-threaded libbinder");
+ // mMaxIncomingThreads should not change from here to its use below,
+ // since we set mStartedSetup==true and setMaxIncomingThreads checks
+ // for that
+ }
}
if (auto status = initShutdownTrigger(); status != OK) return status;
@@ -488,7 +501,7 @@
sp<RpcSession>::fromExisting(this), &version);
status != OK)
return status;
- if (!setProtocolVersion(version)) return BAD_VALUE;
+ if (!setProtocolVersionInternal(version, false)) return BAD_VALUE;
}
// TODO(b/189955605): we should add additional sessions dynamically
@@ -506,11 +519,7 @@
return status;
}
-#ifdef BINDER_RPC_SINGLE_THREADED
- constexpr size_t outgoingThreads = 1;
-#else // BINDER_RPC_SINGLE_THREADED
size_t outgoingThreads = std::min(numThreadsAvailable, mMaxOutgoingThreads);
-#endif // BINDER_RPC_SINGLE_THREADED
ALOGI_IF(outgoingThreads != numThreadsAvailable,
"Server hints client to start %zu outgoing threads, but client will only start %zu "
"because it is preconfigured to start at most %zu outgoing threads.",
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 7cc58cd..51326f6 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -24,6 +24,7 @@
#include "FdTrigger.h"
#include "RpcState.h"
+#include "RpcTransportUtils.h"
namespace android {
@@ -55,90 +56,6 @@
return OK;
}
- template <typename SendOrReceive>
- status_t interruptableReadOrWrite(
- FdTrigger* fdTrigger, iovec* iovs, int niovs, SendOrReceive sendOrReceiveFun,
- const char* funName, int16_t event,
- const std::optional<android::base::function_ref<status_t()>>& altPoll) {
- MAYBE_WAIT_IN_FLAKE_MODE;
-
- if (niovs < 0) {
- return BAD_VALUE;
- }
-
- // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
- // may never know we should be shutting down.
- if (fdTrigger->isTriggered()) {
- return DEAD_OBJECT;
- }
-
- // If iovs has one or more empty vectors at the end and
- // we somehow advance past all the preceding vectors and
- // pass some or all of the empty ones to sendmsg/recvmsg,
- // the call will return processSize == 0. In that case
- // we should be returning OK but instead return DEAD_OBJECT.
- // To avoid this problem, we make sure here that the last
- // vector at iovs[niovs - 1] has a non-zero length.
- while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
- niovs--;
- }
- if (niovs == 0) {
- // The vectors are all empty, so we have nothing to send.
- return OK;
- }
-
- bool havePolled = false;
- while (true) {
- ssize_t processSize = sendOrReceiveFun(iovs, niovs);
- if (processSize < 0) {
- int savedErrno = errno;
-
- // Still return the error on later passes, since it would expose
- // a problem with polling
- if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
- LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
- return -savedErrno;
- }
- } else if (processSize == 0) {
- return DEAD_OBJECT;
- } else {
- while (processSize > 0 && niovs > 0) {
- auto& iov = iovs[0];
- if (static_cast<size_t>(processSize) < iov.iov_len) {
- // Advance the base of the current iovec
- iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
- iov.iov_len -= processSize;
- break;
- }
-
- // The current iovec was fully written
- processSize -= iov.iov_len;
- iovs++;
- niovs--;
- }
- if (niovs == 0) {
- LOG_ALWAYS_FATAL_IF(processSize > 0,
- "Reached the end of iovecs "
- "with %zd bytes remaining",
- processSize);
- return OK;
- }
- }
-
- if (altPoll) {
- if (status_t status = (*altPoll)(); status != OK) return status;
- if (fdTrigger->isTriggered()) {
- return DEAD_OBJECT;
- }
- } else {
- if (status_t status = fdTrigger->triggerablePoll(mSocket.get(), event);
- status != OK)
- return status;
- if (!havePolled) havePolled = true;
- }
- }
- }
-
status_t interruptableWriteFully(
FdTrigger* fdTrigger, iovec* iovs, int niovs,
const std::optional<android::base::function_ref<status_t()>>& altPoll,
@@ -198,7 +115,8 @@
};
return TEMP_FAILURE_RETRY(sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
};
- return interruptableReadOrWrite(fdTrigger, iovs, niovs, send, "sendmsg", POLLOUT, altPoll);
+ return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, send, "sendmsg",
+ POLLOUT, altPoll);
}
status_t interruptableReadFully(
@@ -255,7 +173,8 @@
};
return TEMP_FAILURE_RETRY(recvmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
};
- return interruptableReadOrWrite(fdTrigger, iovs, niovs, recv, "recvmsg", POLLIN, altPoll);
+ return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, recv, "recvmsg",
+ POLLIN, altPoll);
}
private:
diff --git a/libs/binder/RpcTransportUtils.h b/libs/binder/RpcTransportUtils.h
new file mode 100644
index 0000000..00cb2af
--- /dev/null
+++ b/libs/binder/RpcTransportUtils.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 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 <android-base/unique_fd.h>
+#include <poll.h>
+
+#include "FdTrigger.h"
+#include "RpcState.h"
+
+namespace android {
+
+template <typename SendOrReceive>
+status_t interruptableReadOrWrite(
+ int socketFd, FdTrigger* fdTrigger, iovec* iovs, int niovs, SendOrReceive sendOrReceiveFun,
+ const char* funName, int16_t event,
+ const std::optional<android::base::function_ref<status_t()>>& altPoll) {
+ MAYBE_WAIT_IN_FLAKE_MODE;
+
+ if (niovs < 0) {
+ return BAD_VALUE;
+ }
+
+ // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
+ // may never know we should be shutting down.
+ if (fdTrigger->isTriggered()) {
+ return DEAD_OBJECT;
+ }
+
+ // If iovs has one or more empty vectors at the end and
+ // we somehow advance past all the preceding vectors and
+ // pass some or all of the empty ones to sendmsg/recvmsg,
+ // the call will return processSize == 0. In that case
+ // we should be returning OK but instead return DEAD_OBJECT.
+ // To avoid this problem, we make sure here that the last
+ // vector at iovs[niovs - 1] has a non-zero length.
+ while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
+ niovs--;
+ }
+ if (niovs == 0) {
+ // The vectors are all empty, so we have nothing to send.
+ return OK;
+ }
+
+ bool havePolled = false;
+ while (true) {
+ ssize_t processSize = sendOrReceiveFun(iovs, niovs);
+ if (processSize < 0) {
+ int savedErrno = errno;
+
+ // Still return the error on later passes, since it would expose
+ // a problem with polling
+ if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
+ LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
+ return -savedErrno;
+ }
+ } else if (processSize == 0) {
+ return DEAD_OBJECT;
+ } else {
+ while (processSize > 0 && niovs > 0) {
+ auto& iov = iovs[0];
+ if (static_cast<size_t>(processSize) < iov.iov_len) {
+ // Advance the base of the current iovec
+ iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
+ iov.iov_len -= processSize;
+ break;
+ }
+
+ // The current iovec was fully written
+ processSize -= iov.iov_len;
+ iovs++;
+ niovs--;
+ }
+ if (niovs == 0) {
+ LOG_ALWAYS_FATAL_IF(processSize > 0,
+ "Reached the end of iovecs "
+ "with %zd bytes remaining",
+ processSize);
+ return OK;
+ }
+ }
+
+ if (altPoll) {
+ if (status_t status = (*altPoll)(); status != OK) return status;
+ if (fdTrigger->isTriggered()) {
+ return DEAD_OBJECT;
+ }
+ } else {
+ if (status_t status = fdTrigger->triggerablePoll(socketFd, event); status != OK)
+ return status;
+ if (!havePolled) havePolled = true;
+ }
+ }
+}
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 9d94e00..428e272 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -207,6 +207,10 @@
friend RpcState;
explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx);
+ // internal version of setProtocolVersion that
+ // optionally skips the mStartedSetup check
+ [[nodiscard]] bool setProtocolVersionInternal(uint32_t version, bool checkStarted);
+
// for 'target', see RpcState::sendDecStrongToTarget
[[nodiscard]] status_t sendDecStrongToTarget(uint64_t address, size_t target);
@@ -344,6 +348,7 @@
RpcMutex mMutex; // for all below
+ bool mStartedSetup = false;
size_t mMaxIncomingThreads = 0;
size_t mMaxOutgoingThreads = kDefaultMaxOutgoingThreads;
std::optional<uint32_t> mProtocolVersion;
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index b21a7e9..9778ec0 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -64,6 +64,9 @@
wp<ABpBinder> binder;
};
void clean(const void* id, void* obj, void* cookie) {
+ // be weary of leaks!
+ // LOG(INFO) << "Deleting an ABpBinder";
+
CHECK(id == kId) << id << " " << obj << " " << cookie;
delete static_cast<Value*>(obj);
@@ -239,26 +242,11 @@
}
ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder)
- : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
+ : AIBinder(nullptr /*clazz*/), mRemote(binder) {
CHECK(binder != nullptr);
}
ABpBinder::~ABpBinder() {}
-void ABpBinder::onLastStrongRef(const void* id) {
- // Since ABpBinder is OBJECT_LIFETIME_WEAK, we must remove this weak reference in order for
- // the ABpBinder to be deleted. Even though we have no more references on the ABpBinder
- // (BpRefBase), the remote object may still exist (for instance, if we
- // receive it from another process, before the ABpBinder is attached).
-
- ABpBinderTag::Value* value =
- static_cast<ABpBinderTag::Value*>(remote()->findObject(ABpBinderTag::kId));
- CHECK_NE(nullptr, value) << "ABpBinder must always be attached";
-
- remote()->withLock([&]() { value->binder = nullptr; });
-
- BpRefBase::onLastStrongRef(id);
-}
-
sp<AIBinder> ABpBinder::lookupOrCreateFromBinder(const ::android::sp<::android::IBinder>& binder) {
if (binder == nullptr) {
return nullptr;
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 730e51b..d7098e8 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -91,7 +91,7 @@
// This binder object may be remote or local (even though it is 'Bp'). The implication if it is
// local is that it is an IBinder object created outside of the domain of libbinder_ndk.
-struct ABpBinder : public AIBinder, public ::android::BpRefBase {
+struct ABpBinder : public AIBinder {
// Looks up to see if this object has or is an existing ABBinder or ABpBinder object, otherwise
// it creates an ABpBinder object.
static ::android::sp<AIBinder> lookupOrCreateFromBinder(
@@ -99,14 +99,13 @@
virtual ~ABpBinder();
- void onLastStrongRef(const void* id) override;
-
- ::android::sp<::android::IBinder> getBinder() override { return remote(); }
+ ::android::sp<::android::IBinder> getBinder() override { return mRemote; }
ABpBinder* asABpBinder() override { return this; }
private:
friend android::sp<ABpBinder>;
explicit ABpBinder(const ::android::sp<::android::IBinder>& binder);
+ ::android::sp<::android::IBinder> mRemote;
};
struct AIBinder_Class {
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 355b3b4..c0d4487 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -15,9 +15,10 @@
"libutils",
],
rustlibs: [
- "liblibc",
"libbinder_ndk_sys",
"libdowncast_rs",
+ "liblazy_static",
+ "liblibc",
],
host_supported: true,
vendor_available: true,
@@ -148,6 +149,7 @@
name: "libbinder_rpc_unstable_bindgen",
wrapper_src: ":libbinder_rpc_unstable_header",
crate_name: "binder_rpc_unstable_bindgen",
+ visibility: ["//packages/modules/Virtualization:__subpackages__"],
source_stem: "bindings",
shared_libs: [
"libutils",
@@ -170,9 +172,10 @@
"libbinder_ndk",
],
rustlibs: [
- "liblibc",
"libbinder_ndk_sys",
"libdowncast_rs",
+ "liblazy_static",
+ "liblibc",
],
}
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
index 9dcef42..2d2bf7c 100644
--- a/libs/binder/rust/binder_tokio/lib.rs
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -28,22 +28,22 @@
//!
//! [`Tokio`]: crate::Tokio
-use binder::{BinderAsyncPool, BoxFuture, FromIBinder, StatusCode, Strong};
use binder::binder_impl::BinderAsyncRuntime;
+use binder::{BinderAsyncPool, BoxFuture, FromIBinder, StatusCode, Strong};
use std::future::Future;
/// Retrieve an existing service for a particular interface, sleeping for a few
/// seconds if it doesn't yet exist.
-pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(
+ name: &str,
+) -> Result<Strong<T>, StatusCode> {
if binder::is_handling_transaction() {
// See comment in the BinderAsyncPool impl.
return binder::get_interface::<T>(name);
}
let name = name.to_string();
- let res = tokio::task::spawn_blocking(move || {
- binder::get_interface::<T>(&name)
- }).await;
+ let res = tokio::task::spawn_blocking(move || binder::get_interface::<T>(&name)).await;
// The `is_panic` branch is not actually reachable in Android as we compile
// with `panic = abort`.
@@ -58,16 +58,16 @@
/// Retrieve an existing service for a particular interface, or start it if it
/// is configured as a dynamic service and isn't yet started.
-pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(
+ name: &str,
+) -> Result<Strong<T>, StatusCode> {
if binder::is_handling_transaction() {
// See comment in the BinderAsyncPool impl.
return binder::wait_for_interface::<T>(name);
}
let name = name.to_string();
- let res = tokio::task::spawn_blocking(move || {
- binder::wait_for_interface::<T>(&name)
- }).await;
+ let res = tokio::task::spawn_blocking(move || binder::wait_for_interface::<T>(&name)).await;
// The `is_panic` branch is not actually reachable in Android as we compile
// with `panic = abort`.
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 5d6206d..63c8684 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -17,7 +17,7 @@
//! Trait definitions for binder objects
use crate::error::{status_t, Result, StatusCode};
-use crate::parcel::{Parcel, BorrowedParcel};
+use crate::parcel::{BorrowedParcel, Parcel};
use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
use crate::sys;
@@ -133,7 +133,7 @@
match stability {
0 => Ok(Local),
1 => Ok(Vintf),
- _ => Err(StatusCode::BAD_VALUE)
+ _ => Err(StatusCode::BAD_VALUE),
}
}
}
@@ -158,7 +158,12 @@
/// Handle and reply to a request to invoke a transaction on this object.
///
/// `reply` may be [`None`] if the sender does not expect a reply.
- fn on_transact(&self, code: TransactionCode, data: &BorrowedParcel<'_>, reply: &mut BorrowedParcel<'_>) -> Result<()>;
+ fn on_transact(
+ &self,
+ code: TransactionCode,
+ data: &BorrowedParcel<'_>,
+ reply: &mut BorrowedParcel<'_>,
+ ) -> Result<()>;
/// Handle a request to invoke the dump transaction on this
/// object.
@@ -454,28 +459,19 @@
/// Construct a new weak reference from a strong reference
fn new(binder: &Strong<I>) -> Self {
let weak_binder = binder.as_binder().downgrade();
- Weak {
- weak_binder,
- interface_type: PhantomData,
- }
+ Weak { weak_binder, interface_type: PhantomData }
}
/// Upgrade this weak reference to a strong reference if the binder object
/// is still alive
pub fn upgrade(&self) -> Result<Strong<I>> {
- self.weak_binder
- .promote()
- .ok_or(StatusCode::DEAD_OBJECT)
- .and_then(FromIBinder::try_from)
+ self.weak_binder.promote().ok_or(StatusCode::DEAD_OBJECT).and_then(FromIBinder::try_from)
}
}
impl<I: FromIBinder + ?Sized> Clone for Weak<I> {
fn clone(&self) -> Self {
- Self {
- weak_binder: self.weak_binder.clone(),
- interface_type: PhantomData,
- }
+ Self { weak_binder: self.weak_binder.clone(), interface_type: PhantomData }
}
}
@@ -614,7 +610,12 @@
/// contains a `T` pointer in its user data. fd should be a non-owned file
/// descriptor, and args must be an array of null-terminated string
/// poiinters with length num_args.
- unsafe extern "C" fn on_dump(binder: *mut sys::AIBinder, fd: i32, args: *mut *const c_char, num_args: u32) -> status_t;
+ unsafe extern "C" fn on_dump(
+ binder: *mut sys::AIBinder,
+ fd: i32,
+ args: *mut *const c_char,
+ num_args: u32,
+ ) -> status_t;
}
/// Interface for transforming a generic SpIBinder into a specific remote
diff --git a/libs/binder/rust/src/binder_async.rs b/libs/binder/rust/src/binder_async.rs
index 579f9f9..d90acaf 100644
--- a/libs/binder/rust/src/binder_async.rs
+++ b/libs/binder/rust/src/binder_async.rs
@@ -41,7 +41,10 @@
/// boxed `Future` trait object, and including `after_spawn` in the trait function
/// allows the caller to avoid double-boxing if they want to do anything to the value
/// returned from the spawned thread.
- fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
+ fn spawn<'a, F1, F2, Fut, A, B, E>(
+ spawn_me: F1,
+ after_spawn: F2,
+ ) -> BoxFuture<'a, Result<B, E>>
where
F1: FnOnce() -> A,
F2: FnOnce(A) -> Fut,
diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs
index 2598ebc..f6b09ed 100644
--- a/libs/binder/rust/src/error.rs
+++ b/libs/binder/rust/src/error.rs
@@ -18,7 +18,7 @@
use crate::sys;
use std::error;
-use std::ffi::CStr;
+use std::ffi::{CStr, CString};
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::result;
@@ -104,6 +104,10 @@
// A thread-local `AStatus` would not be valid.
unsafe impl Send for Status {}
+fn to_cstring<T: AsRef<str>>(message: T) -> Option<CString> {
+ CString::new(message.as_ref()).ok()
+}
+
impl Status {
/// Create a status object representing a successful transaction.
pub fn ok() -> Self {
@@ -146,6 +150,11 @@
Self(ptr)
}
+ /// Creates a status object from a service specific error.
+ pub fn new_service_specific_error_str<T: AsRef<str>>(err: i32, message: Option<T>) -> Status {
+ Self::new_service_specific_error(err, message.and_then(to_cstring).as_deref())
+ }
+
/// Create a status object from an exception code
pub fn new_exception(exception: ExceptionCode, message: Option<&CStr>) -> Status {
if let Some(message) = message {
@@ -158,6 +167,14 @@
}
}
+ /// Creates a status object from an exception code and message.
+ pub fn new_exception_str<T: AsRef<str>>(
+ exception: ExceptionCode,
+ message: Option<T>,
+ ) -> Status {
+ Self::new_exception(exception, message.and_then(to_cstring).as_deref())
+ }
+
/// Create a status object from a raw `AStatus` pointer.
///
/// # Safety
@@ -371,3 +388,41 @@
self.0
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn make_service_specific_error() {
+ let status = Status::new_service_specific_error_str(-42, Some("message"));
+
+ assert!(!status.is_ok());
+ assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC);
+ assert_eq!(status.service_specific_error(), -42);
+ assert_eq!(
+ status.get_description(),
+ "Status(-8, EX_SERVICE_SPECIFIC): '-42: message'".to_string()
+ );
+ }
+
+ #[test]
+ fn make_exception() {
+ let status = Status::new_exception_str(ExceptionCode::ILLEGAL_STATE, Some("message"));
+
+ assert!(!status.is_ok());
+ assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE);
+ assert_eq!(status.service_specific_error(), 0);
+ assert_eq!(status.get_description(), "Status(-5, EX_ILLEGAL_STATE): 'message'".to_string());
+ }
+
+ #[test]
+ fn make_exception_null() {
+ let status = Status::new_exception_str(ExceptionCode::ILLEGAL_STATE, Some("one\0two"));
+
+ assert!(!status.is_ok());
+ assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE);
+ assert_eq!(status.service_specific_error(), 0);
+ assert_eq!(status.get_description(), "Status(-5, EX_ILLEGAL_STATE): ''".to_string());
+ }
+}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index dbfb1c2..195d9ac 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -106,11 +106,12 @@
use binder_ndk_sys as sys;
-pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
pub use crate::binder_async::{BinderAsyncPool, BoxFuture};
+pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
pub use error::{ExceptionCode, Status, StatusCode};
pub use native::{
add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service,
+ LazyServiceGuard,
};
pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
pub use proxy::{
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 3edeebf..3a6dadd 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -22,6 +22,7 @@
use crate::proxy::SpIBinder;
use crate::sys;
+use lazy_static::lazy_static;
use std::convert::TryFrom;
use std::ffi::{c_void, CStr, CString};
use std::fs::File;
@@ -30,6 +31,7 @@
use std::os::raw::c_char;
use std::os::unix::io::FromRawFd;
use std::slice;
+use std::sync::Mutex;
/// Rust wrapper around Binder remotable objects.
///
@@ -97,10 +99,7 @@
// ends.
sys::AIBinder_new(class.into(), rust_object as *mut c_void)
};
- let mut binder = Binder {
- ibinder,
- rust_object,
- };
+ let mut binder = Binder { ibinder, rust_object };
binder.mark_stability(stability);
binder
}
@@ -343,7 +342,9 @@
vec![]
} else {
slice::from_raw_parts(args, num_args as usize)
- .iter().map(|s| CStr::from_ptr(*s)).collect()
+ .iter()
+ .map(|s| CStr::from_ptr(*s))
+ .collect()
};
let object = sys::AIBinder_getUserData(binder);
@@ -418,10 +419,7 @@
// We are transferring the ownership of the AIBinder into the new Binder
// object.
let mut ibinder = ManuallyDrop::new(ibinder);
- Ok(Binder {
- ibinder: ibinder.as_native_mut(),
- rust_object: userdata as *mut B,
- })
+ Ok(Binder { ibinder: ibinder.as_native_mut(), rust_object: userdata as *mut B })
}
}
@@ -491,6 +489,8 @@
/// If persist is true then shut down will be blocked until this function is called again with
/// persist false. If this is to be the initial state, call this function before calling
/// register_lazy_service.
+///
+/// Consider using [`LazyServiceGuard`] rather than calling this directly.
pub fn force_lazy_services_persist(persist: bool) {
unsafe {
// Safety: No borrowing or transfer of ownership occurs here.
@@ -498,6 +498,59 @@
}
}
+/// An RAII object to ensure a process which registers lazy services is not killed. During the
+/// lifetime of any of these objects the service manager will not not kill the process even if none
+/// of its lazy services are in use.
+#[must_use]
+#[derive(Debug)]
+pub struct LazyServiceGuard {
+ // Prevent construction outside this module.
+ _private: (),
+}
+
+lazy_static! {
+ // Count of how many LazyServiceGuard objects are in existence.
+ static ref GUARD_COUNT: Mutex<u64> = Mutex::new(0);
+}
+
+impl LazyServiceGuard {
+ /// Create a new LazyServiceGuard to prevent the service manager prematurely killing this
+ /// process.
+ pub fn new() -> Self {
+ let mut count = GUARD_COUNT.lock().unwrap();
+ *count += 1;
+ if *count == 1 {
+ // It's important that we make this call with the mutex held, to make sure
+ // that multiple calls (e.g. if the count goes 1 -> 0 -> 1) are correctly
+ // sequenced. (That also means we can't just use an AtomicU64.)
+ force_lazy_services_persist(true);
+ }
+ Self { _private: () }
+ }
+}
+
+impl Drop for LazyServiceGuard {
+ fn drop(&mut self) {
+ let mut count = GUARD_COUNT.lock().unwrap();
+ *count -= 1;
+ if *count == 0 {
+ force_lazy_services_persist(false);
+ }
+ }
+}
+
+impl Clone for LazyServiceGuard {
+ fn clone(&self) -> Self {
+ Self::new()
+ }
+}
+
+impl Default for LazyServiceGuard {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
/// Tests often create a base BBinder instance; so allowing the unit
/// type to be remotable translates nicely to Binder::new(()).
impl Remotable for () {
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 256fa8b..53a24af 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -22,10 +22,10 @@
use crate::sys;
use std::convert::TryInto;
+use std::fmt;
use std::marker::PhantomData;
use std::mem::ManuallyDrop;
use std::ptr::{self, NonNull};
-use std::fmt;
mod file_descriptor;
mod parcelable;
@@ -33,8 +33,8 @@
pub use self::file_descriptor::ParcelFileDescriptor;
pub use self::parcelable::{
- Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
- Parcelable, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
+ Deserialize, DeserializeArray, DeserializeOption, Parcelable, Serialize, SerializeArray,
+ SerializeOption, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
};
pub use self::parcelable_holder::{ParcelableHolder, ParcelableMetadata};
@@ -78,9 +78,7 @@
// a valid pointer. If it fails, the process will crash.
sys::AParcel_create()
};
- Self {
- ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer")
- }
+ Self { ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer") }
}
/// Create an owned reference to a parcel object from a raw pointer.
@@ -116,10 +114,7 @@
// lifetime of the returned `BorrowedParcel` is tied to `self`, so the
// borrow checker will ensure that the `AParcel` can only be accessed
// via the `BorrowParcel` until it goes out of scope.
- BorrowedParcel {
- ptr: self.ptr,
- _lifetime: PhantomData,
- }
+ BorrowedParcel { ptr: self.ptr, _lifetime: PhantomData }
}
/// Get an immutable borrowed view into the contents of this `Parcel`.
@@ -127,9 +122,7 @@
// Safety: Parcel and BorrowedParcel are both represented in the same
// way as a NonNull<sys::AParcel> due to their use of repr(transparent),
// so casting references as done here is valid.
- unsafe {
- &*(self as *const Parcel as *const BorrowedParcel<'_>)
- }
+ unsafe { &*(self as *const Parcel as *const BorrowedParcel<'_>) }
}
}
@@ -165,10 +158,7 @@
/// since this is a mutable borrow, it must have exclusive access to the
/// AParcel for the duration of the borrow.
pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<BorrowedParcel<'a>> {
- Some(Self {
- ptr: NonNull::new(ptr)?,
- _lifetime: PhantomData,
- })
+ Some(Self { ptr: NonNull::new(ptr)?, _lifetime: PhantomData })
}
/// Get a sub-reference to this reference to the parcel.
@@ -177,10 +167,7 @@
// lifetime of the returned `BorrowedParcel` is tied to `self`, so the
// borrow checker will ensure that the `AParcel` can only be accessed
// via the `BorrowParcel` until it goes out of scope.
- BorrowedParcel {
- ptr: self.ptr,
- _lifetime: PhantomData,
- }
+ BorrowedParcel { ptr: self.ptr, _lifetime: PhantomData }
}
}
@@ -269,7 +256,7 @@
/// ```
pub fn sized_write<F>(&mut self, f: F) -> Result<()>
where
- for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
+ for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>,
{
let start = self.get_data_position();
self.write(&0i32)?;
@@ -324,17 +311,17 @@
///
/// This appends `size` bytes of data from `other` starting at offset
/// `start` to the current parcel, or returns an error if not possible.
- pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+ pub fn append_from(
+ &mut self,
+ other: &impl AsNative<sys::AParcel>,
+ start: i32,
+ size: i32,
+ ) -> Result<()> {
let status = unsafe {
// Safety: `Parcel::appendFrom` from C++ checks that `start`
// and `size` are in bounds, and returns an error otherwise.
// Both `self` and `other` always contain valid pointers.
- sys::AParcel_appendFrom(
- other.as_native(),
- self.as_native_mut(),
- start,
- size,
- )
+ sys::AParcel_appendFrom(other.as_native(), self.as_native_mut(), start, size)
};
status_result(status)
}
@@ -406,7 +393,7 @@
/// ```
pub fn sized_write<F>(&mut self, f: F) -> Result<()>
where
- for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
+ for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>,
{
self.borrowed().sized_write(f)
}
@@ -438,7 +425,12 @@
///
/// This appends `size` bytes of data from `other` starting at offset
/// `start` to the current parcel, or returns an error if not possible.
- pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+ pub fn append_from(
+ &mut self,
+ other: &impl AsNative<sys::AParcel>,
+ start: i32,
+ size: i32,
+ ) -> Result<()> {
self.borrowed().append_from(other, start, size)
}
@@ -492,7 +484,7 @@
///
pub fn sized_read<F>(&self, f: F) -> Result<()>
where
- for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+ for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>,
{
let start = self.get_data_position();
let parcelable_size: i32 = self.read()?;
@@ -500,17 +492,13 @@
return Err(StatusCode::BAD_VALUE);
}
- let end = start.checked_add(parcelable_size)
- .ok_or(StatusCode::BAD_VALUE)?;
+ let end = start.checked_add(parcelable_size).ok_or(StatusCode::BAD_VALUE)?;
if end > self.get_data_size() {
return Err(StatusCode::NOT_ENOUGH_DATA);
}
let subparcel = ReadableSubParcel {
- parcel: BorrowedParcel {
- ptr: self.ptr,
- _lifetime: PhantomData,
- },
+ parcel: BorrowedParcel { ptr: self.ptr, _lifetime: PhantomData },
end_position: end,
};
f(subparcel)?;
@@ -633,7 +621,7 @@
///
pub fn sized_read<F>(&self, f: F) -> Result<()>
where
- for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+ for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>,
{
self.borrowed_ref().sized_read(f)
}
@@ -716,15 +704,13 @@
impl fmt::Debug for Parcel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Parcel")
- .finish()
+ f.debug_struct("Parcel").finish()
}
}
impl<'a> fmt::Debug for BorrowedParcel<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("BorrowedParcel")
- .finish()
+ f.debug_struct("BorrowedParcel").finish()
}
}
@@ -813,10 +799,7 @@
assert!(parcel.set_data_position(start).is_ok());
}
- assert_eq!(
- parcel.read::<f32>().unwrap(),
- 1143139100000000000000000000.0
- );
+ assert_eq!(parcel.read::<f32>().unwrap(), 1143139100000000000000000000.0);
assert_eq!(parcel.read::<f32>().unwrap(), 40.043392);
unsafe {
@@ -842,10 +825,7 @@
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
- assert_eq!(
- parcel.read::<Option<String>>().unwrap().unwrap(),
- "Hello, Binder!",
- );
+ assert_eq!(parcel.read::<Option<String>>().unwrap().unwrap(), "Hello, Binder!",);
unsafe {
assert!(parcel.set_data_position(start).is_ok());
}
@@ -864,13 +844,7 @@
assert!(parcel.write(&["str1", "str2", "str3"][..]).is_ok());
assert!(parcel
- .write(
- &[
- String::from("str4"),
- String::from("str5"),
- String::from("str6"),
- ][..]
- )
+ .write(&[String::from("str4"), String::from("str5"), String::from("str6"),][..])
.is_ok());
let s1 = "Hello, Binder!";
@@ -882,14 +856,8 @@
assert!(parcel.set_data_position(start).is_ok());
}
- assert_eq!(
- parcel.read::<Vec<String>>().unwrap(),
- ["str1", "str2", "str3"]
- );
- assert_eq!(
- parcel.read::<Vec<String>>().unwrap(),
- ["str4", "str5", "str6"]
- );
+ assert_eq!(parcel.read::<Vec<String>>().unwrap(), ["str1", "str2", "str3"]);
+ assert_eq!(parcel.read::<Vec<String>>().unwrap(), ["str4", "str5", "str6"]);
assert_eq!(parcel.read::<Vec<String>>().unwrap(), [s1, s2, s3]);
}
@@ -900,9 +868,9 @@
let arr = [1i32, 2i32, 3i32];
- parcel.sized_write(|subparcel| {
- subparcel.write(&arr[..])
- }).expect("Could not perform sized write");
+ parcel
+ .sized_write(|subparcel| subparcel.write(&arr[..]))
+ .expect("Could not perform sized write");
// i32 sub-parcel length + i32 array length + 3 i32 elements
let expected_len = 20i32;
@@ -913,15 +881,9 @@
parcel.set_data_position(start).unwrap();
}
- assert_eq!(
- expected_len,
- parcel.read().unwrap(),
- );
+ assert_eq!(expected_len, parcel.read().unwrap(),);
- assert_eq!(
- parcel.read::<Vec<i32>>().unwrap(),
- &arr,
- );
+ assert_eq!(parcel.read::<Vec<i32>>().unwrap(), &arr,);
}
#[test]
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 4d3d59a..de6d649 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -15,7 +15,7 @@
*/
use super::{
- Deserialize, DeserializeArray, DeserializeOption, BorrowedParcel, Serialize, SerializeArray,
+ BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray,
SerializeOption,
};
use crate::binder::AsNative;
@@ -115,10 +115,7 @@
// descriptor. The read function passes ownership of the file
// descriptor to its caller if it was non-null, so we must take
// ownership of the file and ensure that it is eventually closed.
- status_result(sys::AParcel_readParcelFileDescriptor(
- parcel.as_native(),
- &mut fd,
- ))?;
+ status_result(sys::AParcel_readParcelFileDescriptor(parcel.as_native(), &mut fd))?;
}
if fd < 0 {
Ok(None)
@@ -136,9 +133,7 @@
impl Deserialize for ParcelFileDescriptor {
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
- Deserialize::deserialize(parcel)
- .transpose()
- .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+ Deserialize::deserialize(parcel).transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
}
}
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 0c7e48d..c241e4d 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -22,8 +22,8 @@
use std::convert::{TryFrom, TryInto};
use std::ffi::c_void;
+use std::mem::{self, ManuallyDrop, MaybeUninit};
use std::os::raw::{c_char, c_ulong};
-use std::mem::{self, MaybeUninit, ManuallyDrop};
use std::ptr;
use std::slice;
@@ -109,17 +109,14 @@
// so the function signature matches what bindgen generates.
let index = index as usize;
- let slice: &[T] = slice::from_raw_parts(array.cast(), index+1);
+ let slice: &[T] = slice::from_raw_parts(array.cast(), index + 1);
let mut parcel = match BorrowedParcel::from_raw(parcel) {
None => return StatusCode::UNEXPECTED_NULL as status_t,
Some(p) => p,
};
- slice[index].serialize(&mut parcel)
- .err()
- .unwrap_or(StatusCode::OK)
- as status_t
+ slice[index].serialize(&mut parcel).err().unwrap_or(StatusCode::OK) as status_t
}
/// Helper trait for types that can be deserialized as arrays.
@@ -265,10 +262,7 @@
///
/// The opaque data pointer passed to the array read function must be a mutable
/// pointer to an `Option<Vec<MaybeUninit<T>>>`.
-unsafe extern "C" fn allocate_vec<T>(
- data: *mut c_void,
- len: i32,
-) -> bool {
+unsafe extern "C" fn allocate_vec<T>(data: *mut c_void, len: i32) -> bool {
let vec = &mut *(data as *mut Option<Vec<MaybeUninit<T>>>);
if len < 0 {
*vec = None;
@@ -286,7 +280,6 @@
true
}
-
macro_rules! parcelable_primitives {
{
$(
@@ -303,11 +296,7 @@
// has the same alignment and size as T, so the pointer to the vector
// allocation will be compatible.
let mut vec = ManuallyDrop::new(vec);
- Vec::from_raw_parts(
- vec.as_mut_ptr().cast(),
- vec.len(),
- vec.capacity(),
- )
+ Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity())
}
macro_rules! impl_parcelable {
@@ -522,11 +511,7 @@
// `AParcel`. If the string pointer is null,
// `AParcel_writeString` requires that the length is -1 to
// indicate that we want to serialize a null string.
- status_result(sys::AParcel_writeString(
- parcel.as_native_mut(),
- ptr::null(),
- -1,
- ))
+ status_result(sys::AParcel_writeString(parcel.as_native_mut(), ptr::null(), -1))
},
Some(s) => unsafe {
// Safety: `Parcel` always contains a valid pointer to an
@@ -540,10 +525,7 @@
status_result(sys::AParcel_writeString(
parcel.as_native_mut(),
s.as_ptr() as *const c_char,
- s.as_bytes()
- .len()
- .try_into()
- .or(Err(StatusCode::BAD_VALUE))?,
+ s.as_bytes().len().try_into().or(Err(StatusCode::BAD_VALUE))?,
))
},
}
@@ -602,9 +584,7 @@
impl Deserialize for String {
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
- Deserialize::deserialize(parcel)
- .transpose()
- .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+ Deserialize::deserialize(parcel).transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
}
}
@@ -704,10 +684,7 @@
// and `Status` always contains a valid pointer to an `AStatus`, so
// both parameters are valid and safe. This call does not take
// ownership of either of its parameters.
- status_result(sys::AParcel_writeStatusHeader(
- parcel.as_native_mut(),
- self.as_native(),
- ))
+ status_result(sys::AParcel_writeStatusHeader(parcel.as_native_mut(), self.as_native()))
}
}
}
@@ -881,8 +858,7 @@
Ok(())
} else {
use $crate::Parcelable;
- this.get_or_insert_with(Self::default)
- .read_from_parcel(parcel)
+ this.get_or_insert_with(Self::default).read_from_parcel(parcel)
}
}
}
@@ -915,8 +891,8 @@
#[cfg(test)]
mod tests {
- use crate::parcel::Parcel;
use super::*;
+ use crate::parcel::Parcel;
#[test]
fn test_custom_parcelable() {
@@ -934,11 +910,11 @@
impl Deserialize for Custom {
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
Ok(Custom(
- parcel.read()?,
- parcel.read()?,
- parcel.read()?,
- parcel.read::<Option<Vec<String>>>()?.unwrap(),
- ))
+ parcel.read()?,
+ parcel.read()?,
+ parcel.read()?,
+ parcel.read::<Option<Vec<String>>>()?.unwrap(),
+ ))
}
}
@@ -1157,12 +1133,7 @@
assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
- let f32s = [
- std::f32::NAN,
- std::f32::INFINITY,
- 1.23456789,
- std::f32::EPSILON,
- ];
+ let f32s = [std::f32::NAN, std::f32::INFINITY, 1.23456789, std::f32::EPSILON];
unsafe {
assert!(parcel.set_data_position(start).is_ok());
@@ -1178,12 +1149,7 @@
assert!(vec[0].is_nan());
assert_eq!(vec[1..], f32s[1..]);
- let f64s = [
- std::f64::NAN,
- std::f64::INFINITY,
- 1.234567890123456789,
- std::f64::EPSILON,
- ];
+ let f64s = [std::f64::NAN, std::f64::INFINITY, 1.234567890123456789, std::f64::EPSILON];
unsafe {
assert!(parcel.set_data_position(start).is_ok());
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index 432da5d..c829d37 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -48,10 +48,7 @@
#[derive(Debug, Clone)]
enum ParcelableHolderData {
Empty,
- Parcelable {
- parcelable: Arc<dyn AnyParcelable>,
- name: String,
- },
+ Parcelable { parcelable: Arc<dyn AnyParcelable>, name: String },
Parcel(Parcel),
}
@@ -77,10 +74,7 @@
impl ParcelableHolder {
/// Construct a new `ParcelableHolder` with the given stability.
pub fn new(stability: Stability) -> Self {
- Self {
- data: Mutex::new(ParcelableHolderData::Empty),
- stability,
- }
+ Self { data: Mutex::new(ParcelableHolderData::Empty), stability }
}
/// Reset the contents of this `ParcelableHolder`.
@@ -101,10 +95,8 @@
return Err(StatusCode::BAD_VALUE);
}
- *self.data.get_mut().unwrap() = ParcelableHolderData::Parcelable {
- parcelable: p,
- name: T::get_descriptor().into(),
- };
+ *self.data.get_mut().unwrap() =
+ ParcelableHolderData::Parcelable { parcelable: p, name: T::get_descriptor().into() };
Ok(())
}
@@ -130,10 +122,7 @@
let mut data = self.data.lock().unwrap();
match *data {
ParcelableHolderData::Empty => Ok(None),
- ParcelableHolderData::Parcelable {
- ref parcelable,
- ref name,
- } => {
+ ParcelableHolderData::Parcelable { ref parcelable, ref name } => {
if name != parcelable_desc {
return Err(StatusCode::BAD_VALUE);
}
@@ -199,10 +188,7 @@
let mut data = self.data.lock().unwrap();
match *data {
ParcelableHolderData::Empty => parcel.write(&0i32),
- ParcelableHolderData::Parcelable {
- ref parcelable,
- ref name,
- } => {
+ ParcelableHolderData::Parcelable { ref parcelable, ref name } => {
let length_start = parcel.get_data_position();
parcel.write(&0i32)?;
@@ -251,9 +237,7 @@
// TODO: C++ ParcelableHolder accepts sizes up to SIZE_MAX here, but we
// only go up to i32::MAX because that's what our API uses everywhere
let data_start = parcel.get_data_position();
- let data_end = data_start
- .checked_add(data_size)
- .ok_or(StatusCode::BAD_VALUE)?;
+ let data_end = data_start.checked_add(data_size).ok_or(StatusCode::BAD_VALUE)?;
let mut new_parcel = Parcel::new();
new_parcel.append_from(parcel, data_start, data_size)?;
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 4df557b..254efae 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -22,7 +22,8 @@
};
use crate::error::{status_result, Result, StatusCode};
use crate::parcel::{
- Parcel, BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
+ BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize,
+ SerializeArray, SerializeOption,
};
use crate::sys;
@@ -132,6 +133,14 @@
}
}
+fn interface_cast<T: FromIBinder + ?Sized>(service: Option<SpIBinder>) -> Result<Strong<T>> {
+ if let Some(service) = service {
+ FromIBinder::try_from(service)
+ } else {
+ Err(StatusCode::NAME_NOT_FOUND)
+ }
+}
+
pub mod unstable_api {
use super::{sys, SpIBinder};
@@ -431,10 +440,7 @@
impl Deserialize for SpIBinder {
fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<SpIBinder> {
- parcel
- .read_binder()
- .transpose()
- .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+ parcel.read_binder().transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
}
}
@@ -563,6 +569,9 @@
/// The cookie in this struct represents an Arc<F> for the owned callback.
/// This struct owns a ref-count of it, and so does every binder that we
/// have been linked with.
+///
+/// Dropping the `DeathRecipient` will `unlink_to_death` any binders it is
+/// currently linked to.
#[repr(C)]
pub struct DeathRecipient {
recipient: *mut sys::AIBinder_DeathRecipient,
@@ -610,7 +619,10 @@
//
// All uses of linkToDeath in this file correctly increment the
// ref-count that this onUnlinked callback will decrement.
- sys::AIBinder_DeathRecipient_setOnUnlinked(recipient, Some(Self::cookie_decr_refcount::<F>));
+ sys::AIBinder_DeathRecipient_setOnUnlinked(
+ recipient,
+ Some(Self::cookie_decr_refcount::<F>),
+ );
}
DeathRecipient {
recipient,
@@ -776,21 +788,13 @@
/// Retrieve an existing service for a particular interface, blocking for a few
/// seconds if it doesn't yet exist.
pub fn get_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
- let service = get_service(name);
- match service {
- Some(service) => FromIBinder::try_from(service),
- None => Err(StatusCode::NAME_NOT_FOUND),
- }
+ interface_cast(get_service(name))
}
/// Retrieve an existing service for a particular interface, or start it if it
/// is configured as a dynamic service and isn't yet started.
pub fn wait_for_interface<T: FromIBinder + ?Sized>(name: &str) -> Result<Strong<T>> {
- let service = wait_for_service(name);
- match service {
- Some(service) => FromIBinder::try_from(service),
- None => Err(StatusCode::NAME_NOT_FOUND),
- }
+ interface_cast(wait_for_service(name))
}
/// Check if a service is declared (e.g. in a VINTF manifest)
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index 0aef744..cc18741 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -124,7 +124,8 @@
/// kernel is too old to support this feature.
pub fn with_calling_sid<T, F>(check_permission: F) -> T
where
- for<'a> F: FnOnce(Option<&'a std::ffi::CStr>) -> T {
+ for<'a> F: FnOnce(Option<&'a std::ffi::CStr>) -> T,
+ {
// Safety: AIBinder_getCallingSid returns a c-string pointer
// that is valid for a transaction. Also, the string returned
// is thread local. By restricting the lifetime of the CStr
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index c9d6af0..4e10fa9 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -60,9 +60,7 @@
if let Some(extension_name) = extension_name {
let extension =
BnTest::new_binder(TestService::new(&extension_name), BinderFeatures::default());
- service
- .set_extension(&mut extension.as_binder())
- .expect("Could not add extension");
+ service.set_extension(&mut extension.as_binder()).expect("Could not add extension");
}
binder::add_service(&service_name, service.as_binder())
.expect("Could not register service");
@@ -73,10 +71,7 @@
}
fn print_usage() {
- eprintln!(
- "Usage: {} SERVICE_NAME [EXTENSION_NAME]",
- RUST_SERVICE_BINARY
- );
+ eprintln!("Usage: {} SERVICE_NAME [EXTENSION_NAME]", RUST_SERVICE_BINARY);
eprintln!(concat!(
"Spawn a Binder test service identified by SERVICE_NAME,",
" optionally with an extesion named EXTENSION_NAME",
@@ -90,10 +85,7 @@
impl TestService {
fn new(s: &str) -> Self {
- Self {
- s: s.to_string(),
- dump_args: Mutex::new(Vec::new()),
- }
+ Self { s: s.to_string(), dump_args: Mutex::new(Vec::new()) }
}
}
@@ -111,11 +103,15 @@
fn try_from(c: u32) -> Result<Self, Self::Error> {
match c {
_ if c == TestTransactionCode::Test as u32 => Ok(TestTransactionCode::Test),
- _ if c == TestTransactionCode::GetDumpArgs as u32 => Ok(TestTransactionCode::GetDumpArgs),
+ _ if c == TestTransactionCode::GetDumpArgs as u32 => {
+ Ok(TestTransactionCode::GetDumpArgs)
+ }
_ if c == TestTransactionCode::GetSelinuxContext as u32 => {
Ok(TestTransactionCode::GetSelinuxContext)
}
- _ if c == TestTransactionCode::GetIsHandlingTransaction as u32 => Ok(TestTransactionCode::GetIsHandlingTransaction),
+ _ if c == TestTransactionCode::GetIsHandlingTransaction as u32 => {
+ Ok(TestTransactionCode::GetIsHandlingTransaction)
+ }
_ => Err(StatusCode::UNKNOWN_TRANSACTION),
}
}
@@ -200,15 +196,16 @@
TestTransactionCode::Test => reply.write(&service.test()?),
TestTransactionCode::GetDumpArgs => reply.write(&service.get_dump_args()?),
TestTransactionCode::GetSelinuxContext => reply.write(&service.get_selinux_context()?),
- TestTransactionCode::GetIsHandlingTransaction => reply.write(&service.get_is_handling_transaction()?),
+ TestTransactionCode::GetIsHandlingTransaction => {
+ reply.write(&service.get_is_handling_transaction()?)
+ }
}
}
impl ITest for BpTest {
fn test(&self) -> Result<String, StatusCode> {
let reply =
- self.binder
- .transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
+ self.binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
reply.read()
}
@@ -243,31 +240,45 @@
let binder = self.binder.clone();
P::spawn(
move || binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(())),
- |reply| async move { reply?.read() }
+ |reply| async move { reply?.read() },
)
}
fn get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>> {
let binder = self.binder.clone();
P::spawn(
- move || binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(())),
- |reply| async move { reply?.read() }
+ move || {
+ binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(()))
+ },
+ |reply| async move { reply?.read() },
)
}
fn get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>> {
let binder = self.binder.clone();
P::spawn(
- move || binder.transact(TestTransactionCode::GetSelinuxContext as TransactionCode, 0, |_| Ok(())),
- |reply| async move { reply?.read() }
+ move || {
+ binder.transact(
+ TestTransactionCode::GetSelinuxContext as TransactionCode,
+ 0,
+ |_| Ok(()),
+ )
+ },
+ |reply| async move { reply?.read() },
)
}
fn get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>> {
let binder = self.binder.clone();
P::spawn(
- move || binder.transact(TestTransactionCode::GetIsHandlingTransaction as TransactionCode, 0, |_| Ok(())),
- |reply| async move { reply?.read() }
+ move || {
+ binder.transact(
+ TestTransactionCode::GetIsHandlingTransaction as TransactionCode,
+ 0,
+ |_| Ok(()),
+ )
+ },
+ |reply| async move { reply?.read() },
)
}
}
@@ -374,7 +385,7 @@
use binder_tokio::Tokio;
- use super::{BnTest, ITest, IATest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
+ use super::{BnTest, IATest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
pub struct ScopedServiceProcess(Child);
@@ -405,9 +416,7 @@
impl Drop for ScopedServiceProcess {
fn drop(&mut self) {
self.0.kill().expect("Could not kill child process");
- self.0
- .wait()
- .expect("Could not wait for child process to die");
+ self.0.wait().expect("Could not wait for child process to die");
}
}
@@ -428,10 +437,7 @@
);
// The service manager service isn't an ITest, so this must fail.
- assert_eq!(
- binder::get_interface::<dyn ITest>("manager").err(),
- Some(StatusCode::BAD_TYPE)
- );
+ assert_eq!(binder::get_interface::<dyn ITest>("manager").err(), Some(StatusCode::BAD_TYPE));
assert_eq!(
binder::get_interface::<dyn IATest<Tokio>>("manager").err(),
Some(StatusCode::BAD_TYPE)
@@ -450,7 +456,9 @@
Some(StatusCode::NAME_NOT_FOUND)
);
assert_eq!(
- binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").await.err(),
+ binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist")
+ .await
+ .err(),
Some(StatusCode::NAME_NOT_FOUND)
);
@@ -511,8 +519,9 @@
async fn trivial_client_async() {
let service_name = "trivial_client_test";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Strong<dyn IATest<Tokio>> =
- binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+ .await
+ .expect("Did not get manager binder service");
assert_eq!(test_client.test().await.unwrap(), "trivial_client_test");
}
@@ -529,8 +538,9 @@
async fn wait_for_trivial_client_async() {
let service_name = "wait_for_trivial_client_test";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Strong<dyn IATest<Tokio>> =
- binder_tokio::wait_for_interface(service_name).await.expect("Did not get manager binder service");
+ let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::wait_for_interface(service_name)
+ .await
+ .expect("Did not get manager binder service");
assert_eq!(test_client.test().await.unwrap(), "wait_for_trivial_client_test");
}
@@ -539,9 +549,7 @@
let mut out_ptr = ptr::null_mut();
assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
assert!(!out_ptr.is_null());
- CStr::from_ptr(out_ptr)
- .to_str()
- .expect("context was invalid UTF-8")
+ CStr::from_ptr(out_ptr).to_str().expect("context was invalid UTF-8")
}
}
@@ -551,18 +559,16 @@
let _process = ScopedServiceProcess::new(service_name);
let test_client: Strong<dyn ITest> =
binder::get_interface(service_name).expect("Did not get manager binder service");
- assert_eq!(
- test_client.get_selinux_context().unwrap(),
- get_expected_selinux_context()
- );
+ assert_eq!(test_client.get_selinux_context().unwrap(), get_expected_selinux_context());
}
#[tokio::test]
async fn get_selinux_context_async() {
let service_name = "get_selinux_context_async";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Strong<dyn IATest<Tokio>> =
- binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+ .await
+ .expect("Did not get manager binder service");
assert_eq!(
test_client.get_selinux_context().await.unwrap(),
get_expected_selinux_context()
@@ -586,13 +592,11 @@
async fn get_selinux_context_async_to_sync() {
let service_name = "get_selinux_context";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Strong<dyn IATest<Tokio>> =
- binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+ .await
+ .expect("Did not get manager binder service");
let test_client = test_client.into_sync();
- assert_eq!(
- test_client.get_selinux_context().unwrap(),
- get_expected_selinux_context()
- );
+ assert_eq!(test_client.get_selinux_context().unwrap(), get_expected_selinux_context());
}
struct Bools {
@@ -605,10 +609,7 @@
self.binder_died.load(Ordering::Relaxed)
}
fn assert_died(&self) {
- assert!(
- self.is_dead(),
- "Did not receive death notification"
- );
+ assert!(self.is_dead(), "Did not receive death notification");
}
fn assert_dropped(&self) {
assert!(
@@ -639,9 +640,7 @@
let mut death_recipient = {
let flag = binder_died.clone();
- let set_on_drop = SetOnDrop {
- binder_dealloc: binder_dealloc.clone(),
- };
+ let set_on_drop = SetOnDrop { binder_dealloc: binder_dealloc.clone() };
DeathRecipient::new(move || {
flag.store(true, Ordering::Relaxed);
// Force the closure to take ownership of set_on_drop. When the closure is
@@ -650,14 +649,9 @@
})
};
- binder
- .link_to_death(&mut death_recipient)
- .expect("link_to_death failed");
+ binder.link_to_death(&mut death_recipient).expect("link_to_death failed");
- let bools = Bools {
- binder_died,
- binder_dealloc,
- };
+ let bools = Bools { binder_died, binder_dealloc };
(bools, death_recipient)
}
@@ -675,9 +669,7 @@
let (bools, recipient) = register_death_notification(&mut remote);
drop(service_process);
- remote
- .ping_binder()
- .expect_err("Service should have died already");
+ remote.ping_binder().expect_err("Service should have died already");
// Pause to ensure any death notifications get delivered
thread::sleep(Duration::from_secs(1));
@@ -701,22 +693,15 @@
let (bools, mut recipient) = register_death_notification(&mut remote);
- remote
- .unlink_to_death(&mut recipient)
- .expect("Could not unlink death notifications");
+ remote.unlink_to_death(&mut recipient).expect("Could not unlink death notifications");
drop(service_process);
- remote
- .ping_binder()
- .expect_err("Service should have died already");
+ remote.ping_binder().expect_err("Service should have died already");
// Pause to ensure any death notifications get delivered
thread::sleep(Duration::from_secs(1));
- assert!(
- !bools.is_dead(),
- "Received unexpected death notification after unlinking",
- );
+ assert!(!bools.is_dead(), "Received unexpected death notification after unlinking",);
bools.assert_not_dropped();
drop(recipient);
@@ -771,9 +756,7 @@
let dump_args = ["dump", "args", "for", "testing"];
let null_out = File::open("/dev/null").expect("Could not open /dev/null");
- remote
- .dump(&null_out, &dump_args)
- .expect("Could not dump remote service");
+ remote.dump(&null_out, &dump_args).expect("Could not dump remote service");
let remote_args = test_client.get_dump_args().expect("Could not fetched dumped args");
assert_eq!(dump_args, remote_args[..], "Remote args don't match call to dump");
@@ -799,9 +782,7 @@
let mut remote = binder::get_service(service_name);
assert!(remote.is_binder_alive());
- let extension = remote
- .get_extension()
- .expect("Could not check for an extension");
+ let extension = remote.get_extension().expect("Could not check for an extension");
assert!(extension.is_none());
}
@@ -811,9 +792,7 @@
let mut remote = binder::get_service(service_name);
assert!(remote.is_binder_alive());
- let maybe_extension = remote
- .get_extension()
- .expect("Could not check for an extension");
+ let maybe_extension = remote.get_extension().expect("Could not check for an extension");
let extension = maybe_extension.expect("Remote binder did not have an extension");
@@ -850,15 +829,12 @@
#[test]
fn reassociate_rust_binder() {
let service_name = "testing_service";
- let service_ibinder = BnTest::new_binder(
- TestService::new(service_name),
- BinderFeatures::default(),
- )
- .as_binder();
+ let service_ibinder =
+ BnTest::new_binder(TestService::new(service_name), BinderFeatures::default())
+ .as_binder();
- let service: Strong<dyn ITest> = service_ibinder
- .into_interface()
- .expect("Could not reassociate the generic ibinder");
+ let service: Strong<dyn ITest> =
+ service_ibinder.into_interface().expect("Could not reassociate the generic ibinder");
assert_eq!(service.test().unwrap(), service_name);
}
@@ -866,10 +842,7 @@
#[test]
fn weak_binder_upgrade() {
let service_name = "testing_service";
- let service = BnTest::new_binder(
- TestService::new(service_name),
- BinderFeatures::default(),
- );
+ let service = BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
let weak = Strong::downgrade(&service);
@@ -882,10 +855,8 @@
fn weak_binder_upgrade_dead() {
let service_name = "testing_service";
let weak = {
- let service = BnTest::new_binder(
- TestService::new(service_name),
- BinderFeatures::default(),
- );
+ let service =
+ BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
Strong::downgrade(&service)
};
@@ -896,10 +867,7 @@
#[test]
fn weak_binder_clone() {
let service_name = "testing_service";
- let service = BnTest::new_binder(
- TestService::new(service_name),
- BinderFeatures::default(),
- );
+ let service = BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
let weak = Strong::downgrade(&service);
let cloned = weak.clone();
@@ -915,14 +883,10 @@
#[test]
#[allow(clippy::eq_op)]
fn binder_ord() {
- let service1 = BnTest::new_binder(
- TestService::new("testing_service1"),
- BinderFeatures::default(),
- );
- let service2 = BnTest::new_binder(
- TestService::new("testing_service2"),
- BinderFeatures::default(),
- );
+ let service1 =
+ BnTest::new_binder(TestService::new("testing_service1"), BinderFeatures::default());
+ let service2 =
+ BnTest::new_binder(TestService::new("testing_service2"), BinderFeatures::default());
assert!((service1 >= service1));
assert!((service1 <= service1));
@@ -931,20 +895,20 @@
#[test]
fn binder_parcel_mixup() {
- let service1 = BnTest::new_binder(
- TestService::new("testing_service1"),
- BinderFeatures::default(),
- );
- let service2 = BnTest::new_binder(
- TestService::new("testing_service2"),
- BinderFeatures::default(),
- );
+ let service1 =
+ BnTest::new_binder(TestService::new("testing_service1"), BinderFeatures::default());
+ let service2 =
+ BnTest::new_binder(TestService::new("testing_service2"), BinderFeatures::default());
let service1 = service1.as_binder();
let service2 = service2.as_binder();
let parcel = service1.prepare_transact().unwrap();
- let res = service2.submit_transact(super::TestTransactionCode::Test as TransactionCode, parcel, 0);
+ let res = service2.submit_transact(
+ super::TestTransactionCode::Test as TransactionCode,
+ parcel,
+ 0,
+ );
match res {
Ok(_) => panic!("submit_transact should fail"),
@@ -967,15 +931,18 @@
// Should also be false in spawned thread.
std::thread::spawn(|| {
assert!(!binder::is_handling_transaction());
- }).join().unwrap();
+ })
+ .join()
+ .unwrap();
}
#[tokio::test]
async fn get_is_handling_transaction_async() {
let service_name = "get_is_handling_transaction_async";
let _process = ScopedServiceProcess::new(service_name);
- let test_client: Strong<dyn IATest<Tokio>> =
- binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+ let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+ .await
+ .expect("Did not get manager binder service");
// Should be true externally.
assert!(test_client.get_is_handling_transaction().await.unwrap());
@@ -985,11 +952,15 @@
// Should also be false in spawned task.
tokio::spawn(async {
assert!(!binder::is_handling_transaction());
- }).await.unwrap();
+ })
+ .await
+ .unwrap();
// And in spawn_blocking task.
tokio::task::spawn_blocking(|| {
assert!(!binder::is_handling_transaction());
- }).await.unwrap();
+ })
+ .await
+ .unwrap();
}
}
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index f6bdf5c..6220db4 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -23,7 +23,7 @@
};
// Import from impl API for testing only, should not be necessary as long as you
// are using AIDL.
-use binder::binder_impl::{BorrowedParcel, Binder, TransactionCode};
+use binder::binder_impl::{Binder, BorrowedParcel, TransactionCode};
use std::ffi::{c_void, CStr, CString};
use std::sync::Once;
@@ -64,13 +64,7 @@
macro_rules! assert {
($expr:expr) => {
if !$expr {
- eprintln!(
- "assertion failed: `{:?}`, {}:{}:{}",
- $expr,
- file!(),
- line!(),
- column!()
- );
+ eprintln!("assertion failed: `{:?}`, {}:{}:{}", $expr, file!(), line!(), column!());
return Err(StatusCode::FAILED_TRANSACTION);
}
};
@@ -119,9 +113,7 @@
bindings::Transaction_TEST_BOOL => {
assert!(parcel.read::<bool>()?);
assert!(!parcel.read::<bool>()?);
- assert_eq!(parcel.read::<Vec<bool>>()?, unsafe {
- bindings::TESTDATA_BOOL
- });
+ assert_eq!(parcel.read::<Vec<bool>>()?, unsafe { bindings::TESTDATA_BOOL });
assert_eq!(parcel.read::<Option<Vec<bool>>>()?, None);
reply.write(&true)?;
@@ -148,9 +140,7 @@
assert_eq!(parcel.read::<u16>()?, 0);
assert_eq!(parcel.read::<u16>()?, 1);
assert_eq!(parcel.read::<u16>()?, u16::max_value());
- assert_eq!(parcel.read::<Vec<u16>>()?, unsafe {
- bindings::TESTDATA_CHARS
- });
+ assert_eq!(parcel.read::<Vec<u16>>()?, unsafe { bindings::TESTDATA_CHARS });
assert_eq!(parcel.read::<Option<Vec<u16>>>()?, None);
reply.write(&0u16)?;
@@ -163,9 +153,7 @@
assert_eq!(parcel.read::<i32>()?, 0);
assert_eq!(parcel.read::<i32>()?, 1);
assert_eq!(parcel.read::<i32>()?, i32::max_value());
- assert_eq!(parcel.read::<Vec<i32>>()?, unsafe {
- bindings::TESTDATA_I32
- });
+ assert_eq!(parcel.read::<Vec<i32>>()?, unsafe { bindings::TESTDATA_I32 });
assert_eq!(parcel.read::<Option<Vec<i32>>>()?, None);
reply.write(&0i32)?;
@@ -178,9 +166,7 @@
assert_eq!(parcel.read::<i64>()?, 0);
assert_eq!(parcel.read::<i64>()?, 1);
assert_eq!(parcel.read::<i64>()?, i64::max_value());
- assert_eq!(parcel.read::<Vec<i64>>()?, unsafe {
- bindings::TESTDATA_I64
- });
+ assert_eq!(parcel.read::<Vec<i64>>()?, unsafe { bindings::TESTDATA_I64 });
assert_eq!(parcel.read::<Option<Vec<i64>>>()?, None);
reply.write(&0i64)?;
@@ -193,9 +179,7 @@
assert_eq!(parcel.read::<u64>()?, 0);
assert_eq!(parcel.read::<u64>()?, 1);
assert_eq!(parcel.read::<u64>()?, u64::max_value());
- assert_eq!(parcel.read::<Vec<u64>>()?, unsafe {
- bindings::TESTDATA_U64
- });
+ assert_eq!(parcel.read::<Vec<u64>>()?, unsafe { bindings::TESTDATA_U64 });
assert_eq!(parcel.read::<Option<Vec<u64>>>()?, None);
reply.write(&0u64)?;
@@ -232,16 +216,9 @@
let s: Option<String> = parcel.read()?;
assert_eq!(s, None);
let s: Option<Vec<Option<String>>> = parcel.read()?;
- for (s, expected) in s
- .unwrap()
- .iter()
- .zip(unsafe { bindings::TESTDATA_STRS }.iter())
- {
- let expected = unsafe {
- expected
- .as_ref()
- .and_then(|e| CStr::from_ptr(e).to_str().ok())
- };
+ for (s, expected) in s.unwrap().iter().zip(unsafe { bindings::TESTDATA_STRS }.iter()) {
+ let expected =
+ unsafe { expected.as_ref().and_then(|e| CStr::from_ptr(e).to_str().ok()) };
assert_eq!(s.as_deref(), expected);
}
let s: Option<Vec<Option<String>>> = parcel.read()?;
@@ -252,10 +229,7 @@
.iter()
.map(|s| {
s.as_ref().map(|s| {
- CStr::from_ptr(s)
- .to_str()
- .expect("String was not UTF-8")
- .to_owned()
+ CStr::from_ptr(s).to_str().expect("String was not UTF-8").to_owned()
})
})
.collect()
@@ -284,12 +258,8 @@
assert!(ibinders[1].is_none());
assert!(parcel.read::<Option<Vec<Option<SpIBinder>>>>()?.is_none());
- let service = unsafe {
- SERVICE
- .as_ref()
- .expect("Global binder service not initialized")
- .clone()
- };
+ let service =
+ unsafe { SERVICE.as_ref().expect("Global binder service not initialized").clone() };
reply.write(&service)?;
reply.write(&(None as Option<&SpIBinder>))?;
reply.write(&[Some(&service), None][..])?;
@@ -300,10 +270,7 @@
assert!(status.is_ok());
let status: Status = parcel.read()?;
assert_eq!(status.exception_code(), ExceptionCode::NULL_POINTER);
- assert_eq!(
- status.get_description(),
- "Status(-4, EX_NULL_POINTER): 'a status message'"
- );
+ assert_eq!(status.get_description(), "Status(-4, EX_NULL_POINTER): 'a status message'");
let status: Status = parcel.read()?;
assert_eq!(status.service_specific_error(), 42);
assert_eq!(
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index 3b1faa8..cfaf2a9 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -249,12 +249,13 @@
pid_t pid = fork();
if (pid) {
/* parent */
- return move(get<0>(pipe_pair));
+ return std::move(get<0>(pipe_pair));
} else {
/* child */
- worker_fx(num, worker_count, iterations, payload_size, cs_pair, move(get<1>(pipe_pair)));
+ worker_fx(num, worker_count, iterations, payload_size, cs_pair,
+ std::move(get<1>(pipe_pair)));
/* never get here */
- return move(get<0>(pipe_pair));
+ return std::move(get<0>(pipe_pair));
}
}
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
index 56d958c..0035e4e 100644
--- a/libs/binder/tests/schd-dbg.cpp
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -398,14 +398,13 @@
pid_t pid = fork();
if (pid) {
// parent
- return move(get<0>(pipe_pair));
+ return std::move(get<0>(pipe_pair));
} else {
// child
thread_dump(is_client(num) ? "client" : "server");
- worker_fx(num, no_process, iterations, payload_size,
- move(get<1>(pipe_pair)));
+ worker_fx(num, no_process, iterations, payload_size, std::move(get<1>(pipe_pair)));
// never get here
- return move(get<0>(pipe_pair));
+ return std::move(get<0>(pipe_pair));
}
}
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
index e77c55c..910c9dc 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
@@ -49,6 +49,7 @@
});
sp<RpcSession> session = RpcSession::make();
+ session->setMaxIncomingThreads(1);
status_t status;
for (size_t tries = 0; tries < 5; tries++) {
usleep(10000);
diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
index e0d80fb..dc27eb9 100644
--- a/libs/binder/trusty/RpcTransportTipcTrusty.cpp
+++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
@@ -64,7 +64,7 @@
.num_handles = 0, // TODO: add ancillaryFds
.handles = nullptr,
};
- int rc = send_msg(mSocket.get(), &msg);
+ ssize_t rc = send_msg(mSocket.get(), &msg);
if (rc == ERR_NOT_ENOUGH_BUFFER) {
// Peer is blocked, wait until it unblocks.
// TODO: when tipc supports a send-unblocked handler,
@@ -89,7 +89,7 @@
return statusFromTrusty(rc);
}
LOG_ALWAYS_FATAL_IF(static_cast<size_t>(rc) != size,
- "Sent the wrong number of bytes %d!=%zu", rc, size);
+ "Sent the wrong number of bytes %zd!=%zu", rc, size);
return OK;
}
@@ -129,7 +129,7 @@
.num_handles = 0, // TODO: support ancillaryFds
.handles = nullptr,
};
- int rc = read_msg(mSocket.get(), mMessageInfo.id, mMessageOffset, &msg);
+ ssize_t rc = read_msg(mSocket.get(), mMessageInfo.id, mMessageOffset, &msg);
if (rc < 0) {
return statusFromTrusty(rc);
}
diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk
index cd81a09..83475f5 100644
--- a/libs/binder/trusty/rules.mk
+++ b/libs/binder/trusty/rules.mk
@@ -69,6 +69,11 @@
$(LIBUTILS_DIR)/include \
$(FMTLIB_DIR)/include \
+# The android/binder_to_string.h header is shared between libbinder and
+# libbinder_ndk and included by auto-generated AIDL C++ files
+MODULE_EXPORT_INCLUDES += \
+ $(LIBBINDER_DIR)/ndk/include_cpp \
+
MODULE_EXPORT_COMPILEFLAGS += \
-DBINDER_NO_KERNEL_IPC \
-DBINDER_RPC_SINGLE_THREADED \
diff --git a/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/Android.bp b/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/Android.bp
new file mode 100644
index 0000000..2399acd
--- /dev/null
+++ b/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/Android.bp
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ */
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_fuzz {
+ name: "cputimeinstate_fuzzer",
+ srcs: [
+ "cputimeinstate_fuzzer.cpp",
+ ],
+ static_libs: [
+ "libtimeinstate",
+ ],
+ shared_libs: [
+ "libbpf_bcc",
+ "libbase",
+ "libbpf_minimal",
+ ],
+}
diff --git a/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp b/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp
new file mode 100644
index 0000000..f835997
--- /dev/null
+++ b/libs/cputimeinstate/fuzz/cputimeinstate_fuzzer/cputimeinstate_fuzzer.cpp
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 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 <fuzzer/FuzzedDataProvider.h>
+#include <android-base/unique_fd.h>
+#include <cputimeinstate.h>
+
+using namespace android::bpf;
+
+static const uint16_t MAX_VEC_SIZE = 500;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+
+ uint32_t uid = fdp.ConsumeIntegral<uint32_t>();
+ uint64_t lastUpdate = fdp.ConsumeIntegral<uint64_t>();
+ uint16_t aggregationKey = fdp.ConsumeIntegral<uint16_t>();
+ pid_t pid = fdp.ConsumeIntegral<pid_t>();
+ std::vector<uint16_t> aggregationKeys;
+ uint16_t aggregationKeysSize = fdp.ConsumeIntegralInRange<size_t>(0, MAX_VEC_SIZE);
+ for (uint16_t i = 0; i < aggregationKeysSize; i++) {
+ aggregationKeys.push_back(fdp.ConsumeIntegral<uint16_t>());
+ }
+
+ // To randomize the API calls
+ while (fdp.remaining_bytes() > 0) {
+ auto func = fdp.PickValueInArray<const std::function<void()>>({
+ [&]() { getUidCpuFreqTimes(uid); },
+ [&]() { getUidsUpdatedCpuFreqTimes(&lastUpdate); },
+ [&]() { getUidConcurrentTimes(uid);},
+ [&]() { getUidsUpdatedConcurrentTimes(&lastUpdate); },
+ [&]() { startAggregatingTaskCpuTimes(pid, aggregationKey); },
+ [&]() { getAggregatedTaskCpuFreqTimes(pid, aggregationKeys); },
+ });
+
+ func();
+ }
+
+ return 0;
+}
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index d7bc500..e138212 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -184,7 +184,8 @@
],
srcs: [
- ":framework_native_aidl",
+ ":framework_native_aidl_binder",
+ ":framework_native_aidl_gui",
":inputconstants_aidl",
":libgui_bufferqueue_sources",
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 45c958e..31bf895 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -2,9 +2,8 @@
alecmouri@google.com
chaviw@google.com
chrisforbes@google.com
-jessehall@google.com
lpy@google.com
-mathias@google.com
+jreck@google.com
racarr@google.com
vishnun@google.com
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index fef83ea..4b4d46a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1948,6 +1948,7 @@
mReqHeight = 0;
mReqUsage = 0;
mCrop.clear();
+ mDataSpace = Dataspace::UNKNOWN;
mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
mTransform = 0;
mStickyTransform = 0;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index d365851..e8aaf62 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1085,16 +1085,6 @@
return physicalDisplayIds;
}
-status_t SurfaceComposerClient::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) {
- int64_t displayId;
- binder::Status status =
- ComposerServiceAIDL::getComposerService()->getPrimaryPhysicalDisplayId(&displayId);
- if (status.isOk()) {
- *id = *DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
- }
- return statusTFromBinderStatus(status);
-}
-
std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance();
return instance.getInternalDisplayId();
@@ -1279,8 +1269,11 @@
mStatus = BAD_INDEX;
return *this;
}
+ if (alpha < 0.0f || alpha > 1.0f) {
+ ALOGE("SurfaceComposerClient::Transaction::setAlpha: invalid alpha %f, clamping", alpha);
+ }
s->what |= layer_state_t::eAlphaChanged;
- s->alpha = alpha;
+ s->alpha = std::clamp(alpha, 0.f, 1.f);
registerSurfaceControlForCallback(sc);
return *this;
@@ -2177,6 +2170,16 @@
return nullptr;
}
+sp<SurfaceControl> SurfaceComposerClient::mirrorDisplay(DisplayId displayId) {
+ gui::MirrorSurfaceResult result;
+ const binder::Status status = mClient->mirrorDisplay(displayId.value, &result);
+ const status_t err = statusTFromBinderStatus(status);
+ if (err == NO_ERROR) {
+ return new SurfaceControl(this, result.handle, result.layerId);
+ }
+ return nullptr;
+}
+
status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) const {
if (mStatus != NO_ERROR) {
return mStatus;
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index 730d758..3c220fc 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -94,8 +94,6 @@
*/
long[] getPhysicalDisplayIds();
- long getPrimaryPhysicalDisplayId();
-
/**
* Get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or
* a DisplayEventReceiver hotplug event.
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl
index 71933aa..b8ee4d7 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl
@@ -59,4 +59,6 @@
FrameStats getLayerFrameStats(IBinder handle);
MirrorSurfaceResult mirrorSurface(IBinder mirrorFromHandle);
+
+ MirrorSurfaceResult mirrorDisplay(long displayId);
}
diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp
index f1c529d..cdc9376 100644
--- a/libs/gui/fuzzer/Android.bp
+++ b/libs/gui/fuzzer/Android.bp
@@ -85,3 +85,53 @@
"libgui_fuzzer_defaults",
],
}
+
+cc_fuzz {
+ name: "libgui_surfaceComposerClient_fuzzer",
+ srcs: [
+ "libgui_surfaceComposerClient_fuzzer.cpp",
+ ],
+ defaults: [
+ "libgui_fuzzer_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "libgui_parcelable_fuzzer",
+ srcs: [
+ "libgui_parcelable_fuzzer.cpp",
+ ],
+ defaults: [
+ "libgui_fuzzer_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "libgui_bufferQueue_fuzzer",
+ srcs: [
+ "libgui_bufferQueue_fuzzer.cpp",
+ ],
+ defaults: [
+ "libgui_fuzzer_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "libgui_consumer_fuzzer",
+ srcs: [
+ "libgui_consumer_fuzzer.cpp",
+ ],
+ defaults: [
+ "libgui_fuzzer_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "libgui_displayEvent_fuzzer",
+ srcs: [
+ "libgui_displayEvent_fuzzer.cpp",
+ ],
+ defaults: [
+ "libgui_fuzzer_defaults",
+ ],
+}
diff --git a/libs/gui/fuzzer/README.md b/libs/gui/fuzzer/README.md
index c9e8b65..96e27c9 100644
--- a/libs/gui/fuzzer/README.md
+++ b/libs/gui/fuzzer/README.md
@@ -2,6 +2,11 @@
## Table of contents
+ [libgui_surfaceComposer_fuzzer](#SurfaceComposer)
++ [libgui_surfaceComposerClient_fuzzer](#SurfaceComposerClient)
++ [libgui_parcelable_fuzzer](#Libgui_Parcelable)
++ [libgui_bufferQueue_fuzzer](#BufferQueue)
++ [libgui_consumer_fuzzer](#Libgui_Consumer)
++ [libgui_displayEvent_fuzzer](#LibGui_DisplayEvent)
# <a name="libgui_surfaceComposer_fuzzer"></a> Fuzzer for SurfaceComposer
@@ -40,3 +45,175 @@
$ adb sync data
$ adb shell /data/fuzz/arm64/libgui_surfaceComposer_fuzzer/libgui_surfaceComposer_fuzzer
```
+
+# <a name="libgui_surfaceComposerClient_fuzzer"></a> Fuzzer for SurfaceComposerClient
+
+SurfaceComposerClient supports the following data sources:
+1. SurfaceWidth (parameter name:`width`)
+2. SurfaceHeight (parameter name:`height`)
+3. TransactionStateFlags (parameter name:`flags`)
+4. TransformHint (parameter name:`outTransformHint`)
+5. SurfacePixelFormat (parameter name:`format`)
+6. LayerId (parameter name:`outLayerId`)
+7. SurfaceComposerClientTags (parameter name:`surfaceTag`)
+8. DefaultMode (parameter name:`defaultMode`)
+9. PrimaryRefreshRateMin (parameter name:`primaryRefreshRateMin`)
+10. PrimaryRefreshRateMax (parameter name:`primaryRefreshRateMax`)
+11. AppRefreshRateMin (parameter name:`appRefreshRateMin`)
+12. AppRefreshRateMax (parameter name:`appRefreshRateMax`)
+13. DisplayPowerMode (parameter name:`mode`)
+14. CacheId (parameter name:`cacheId`)
+15. DisplayBrightness (parameter name:`brightness`)
+16. PowerBoostID (parameter name:`boostId`)
+17. AtomId (parameter name:`atomId`)
+18. ComponentMask (parameter name:`componentMask`)
+19. MaxFrames (parameter name:`maxFrames`)
+20. TaskId (parameter name:`taskId`)
+21. Alpha (parameter name:`aplha`)
+22. CornerRadius (parameter name:`cornerRadius`)
+23. BackgroundBlurRadius (parameter name:`backgroundBlurRadius`)
+24. Half3Color (parameter name:`color`)
+25. LayerStack (parameter name:`layerStack`)
+26. Dataspace (parameter name:`dataspace`)
+27. Api (parameter name:`api`)
+28. Priority (parameter name:`priority`)
+29. TouchableRegionPointX (parameter name:`pointX`)
+30. TouchableRegionPointY (parameter name:`pointY`)
+31. ColorMode (parameter name:`colorMode`)
+32. WindowInfoFlags (parameter name:`flags`)
+33. WindowInfoTransformOrientation (parameter name:`transform`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`surfaceTag`| 0.`Tag::CREATE_SURFACE`, 1.`Tag::CREATE_WITH_SURFACE_PARENT`, 2.`Tag::CLEAR_LAYER_FRAME_STATS`, 3.`Tag::GET_LAYER_FRAME_STATS`, 4.`Tag::MIRROR_SURFACE`, 5.`Tag::LAST` |Value obtained from FuzzedDataProvider|
+|`mode`| 0.`gui::TouchOcclusionMode::BLOCK_UNTRUSTED`, 1.`gui::TouchOcclusionMode::USE_OPACITY`, 2.`gui::TouchOcclusionMode::ALLOW` |Value obtained from FuzzedDataProvider|
+|`boostId`| 0.`hardware::power::Boost::INTERACTION`, 1.`hardware::power::Boost::DISPLAY_UPDATE_IMMINENT`, 2.`hardware::power::Boost::ML_ACC`, 3.`hardware::power::Boost::AUDIO_LAUNCH`, 4.`hardware::power::Boost::CAMERA_LAUNCH`, 5.`hardware::power::Boost::CAMERA_SHOT` |Value obtained from FuzzedDataProvider|
+|`colorMode`|0.`ui::ColorMode::NATIVE`, 1.`ui::ColorMode::STANDARD_BT601_625`, 2.`ui::ColorMode::STANDARD_BT601_625_UNADJUSTED`, 3.`ui::ColorMode::STANDARD_BT601_525`, 4.`ui::ColorMode::STANDARD_BT601_525_UNADJUSTED`, 5.`ui::ColorMode::STANDARD_BT709`, 6.`ui::ColorMode::DCI_P3`, 7.`ui::ColorMode::SRGB`, 8.`ui::ColorMode::ADOBE_RGB`, 9.`ui::ColorMode::DISPLAY_P3`, 10.`ui::ColorMode::BT2020`, 11.`ui::ColorMode::BT2100_PQ`, 12.`ui::ColorMode::BT2100_HLG`, 13.`ui::ColorMode::DISPLAY_BT2020` |Value obtained from FuzzedDataProvider|
+|`flags`|0 .`gui::WindowInfo::Flag::ALLOW_LOCK_WHILE_SCREEN_ON`, 1.`gui::WindowInfo::Flag::DIM_BEHIND`, 2.`gui::WindowInfo::Flag::BLUR_BEHIND`, 3.`gui::WindowInfo::Flag::NOT_FOCUSABLE`, 4.`gui::WindowInfo::Flag::NOT_TOUCHABLE`, 5.`gui::WindowInfo::Flag::NOT_TOUCH_MODAL`, 6.`gui::WindowInfo::Flag::TOUCHABLE_WHEN_WAKING`, 7.`gui::WindowInfo::Flag::KEEP_SCREEN_ON`, 8.`gui::WindowInfo::Flag::LAYOUT_IN_SCREEN`, 9.`gui::WindowInfo::Flag::LAYOUT_NO_LIMITS`, 10.`gui::WindowInfo::Flag::FULLSCREEN`, 11.`gui::WindowInfo::Flag::FORCE_NOT_FULLSCREEN`, 12.`gui::WindowInfo::Flag::DITHER`, 13.`gui::WindowInfo::Flag::SECURE`, 14.`gui::WindowInfo::Flag::SCALED`, 15.`gui::WindowInfo::Flag::IGNORE_CHEEK_PRESSES`, 16.`gui::WindowInfo::Flag::LAYOUT_INSET_DECOR`, 17.`gui::WindowInfo::Flag::ALT_FOCUSABLE_IM`, 18.`gui::WindowInfo::Flag::WATCH_OUTSIDE_TOUCH`, 19.`gui::WindowInfo::Flag::SHOW_WHEN_LOCKED`, 20.`gui::WindowInfo::Flag::SHOW_WALLPAPER`, 21.`gui::WindowInfo::Flag::TURN_SCREEN_ON`, 22.`gui::WindowInfo::Flag::DISMISS_KEYGUARD`, 23.`gui::WindowInfo::Flag::SPLIT_TOUCH`, 24.`gui::WindowInfo::Flag::HARDWARE_ACCELERATED`, 25.`gui::WindowInfo::Flag::LAYOUT_IN_OVERSCAN`, 26.`gui::WindowInfo::Flag::TRANSLUCENT_STATUS`, 27.`gui::WindowInfo::Flag::TRANSLUCENT_NAVIGATION`, 28.`gui::WindowInfo::Flag::LOCAL_FOCUS_MODE`, 29.`gui::WindowInfo::Flag::SLIPPERY`, 30.`gui::WindowInfo::Flag::LAYOUT_ATTACHED_IN_DECOR`, 31.`gui::WindowInfo::Flag::DRAWS_SYSTEM_BAR_BACKGROUNDS`, |Value obtained from FuzzedDataProvider|
+|`dataspace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider|
+|`transform`| 0.`ui::Transform::ROT_0`, 1.`ui::Transform::FLIP_H`, 2.`ui::Transform::FLIP_V`, 3.`ui::Transform::ROT_90`, 4.`ui::Transform::ROT_180`, 5.`ui::Transform::ROT_270` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) libgui_surfaceComposerClient_fuzzer
+```
+2. To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/libgui_surfaceComposerClient_fuzzer/libgui_surfaceComposerClient_fuzzer
+```
+
+# <a name="libgui_parcelable_fuzzer"></a> Fuzzer for Libgui_Parcelable
+
+Libgui_Parcelable supports the following parameters:
+1. LayerMetadataKey (parameter name:`key`)
+2. Dataspace (parameter name:`mDataspace`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`key`| 0.`view::LayerMetadataKey::METADATA_OWNER_UID`, 1.`view::LayerMetadataKey::METADATA_WINDOW_TYPE`, 2.`view::LayerMetadataKey::METADATA_TASK_ID`, 3.`view::LayerMetadataKey::METADATA_MOUSE_CURSOR`, 4.`view::LayerMetadataKey::METADATA_ACCESSIBILITY_ID`, 5.`view::LayerMetadataKey::METADATA_OWNER_PID`, 6.`view::LayerMetadataKey::METADATA_DEQUEUE_TIME`, 7.`view::LayerMetadataKey::METADATA_GAME_MODE`, |Value obtained from FuzzedDataProvider|
+|`mDataSpace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) libgui_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/libgui_fuzzer/libgui_fuzzer
+```
+
+# <a name="libgui_bufferQueue_fuzzer"></a> Fuzzer for BufferQueue
+
+BufferQueue supports the following parameters:
+1. SurfaceWidth (parameter name:`width`)
+2. SurfaceHeight (parameter name:`height`)
+3. TransactionStateFlags (parameter name:`flags`)
+4. TransformHint (parameter name:`outTransformHint`)
+5. SurfacePixelFormat (parameter name:`format`)
+6. LayerId (parameter name:`layerId`)
+7. BufferId (parameter name:`bufferId`)
+8. FrameNumber (parameter name:`frameNumber`)
+9. FrameRate (parameter name:`frameRate`)
+10. Compatability (parameter name:`compatability`)
+11. LatchTime (parameter name:`latchTime`)
+12. AcquireTime (parameter name:`acquireTime`)
+13. RefreshTime (parameter name:`refreshTime`)
+14. DequeueTime (parameter name:`dequeueTime`)
+15. Slot (parameter name:`slot`)
+16. MaxBuffers (parameter name:`maxBuffers`)
+17. GenerationNumber (parameter name:`generationNumber`)
+18. Api (parameter name:`api`)
+19. Usage (parameter name:`usage`)
+20. MaxFrameNumber (parameter name:`maxFrameNumber`)
+21. BufferCount (parameter name:`bufferCount`)
+22. MaxAcquredBufferCount (parameter name:`maxAcquredBufferCount`)
+23. Status (parameter name:`status`)
+24. ApiConnection (parameter name:`apiConnection`)
+25. Dataspace (parameter name:`dataspace`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`status`| 0.`OK`, 1.`NO_MEMORY`, 2.`NO_INIT`, 3.`BAD_VALUE`, 4.`DEAD_OBJECT`, 5.`INVALID_OPERATION`, 6.`TIMED_OUT`, 7.`WOULD_BLOCK`, 8.`UNKNOWN_ERROR`, 9.`ALREADY_EXISTS`, |Value obtained from FuzzedDataProvider|
+|`apiConnection`| 0.`BufferQueueCore::CURRENTLY_CONNECTED_API`, 1.`BufferQueueCore::NO_CONNECTED_API`, 2.`NATIVE_WINDOW_API_EGL`, 3.`NATIVE_WINDOW_API_CPU`, 4.`NATIVE_WINDOW_API_MEDIA`, 5.`NATIVE_WINDOW_API_CAMERA`, |Value obtained from FuzzedDataProvider|
+|`dataspace`| 0.`ui::Dataspace::UNKNOWN`, 1.`ui::Dataspace::ARBITRARY`, 2.`ui::Dataspace::STANDARD_SHIFT`, 3.`ui::Dataspace::STANDARD_MASK`, 4.`ui::Dataspace::STANDARD_UNSPECIFIED`, 5.`ui::Dataspace::STANDARD_BT709`, 6.`ui::Dataspace::STANDARD_BT601_625`, 7.`ui::Dataspace::STANDARD_BT601_625_UNADJUSTED`, 8.`ui::Dataspace::STANDARD_BT601_525`, 9.`ui::Dataspace::STANDARD_BT601_525_UNADJUSTED`, 10.`ui::Dataspace::STANDARD_BT2020`, 11.`ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE`, 12.`ui::Dataspace::STANDARD_BT470M`, 13.`ui::Dataspace::STANDARD_FILM`, 14.`ui::Dataspace::STANDARD_DCI_P3`, 15.`ui::Dataspace::STANDARD_ADOBE_RGB`, 16.`ui::Dataspace::TRANSFER_SHIFT`, 17.`ui::Dataspace::TRANSFER_MASK`, 18.`ui::Dataspace::TRANSFER_UNSPECIFIED`, 19.`ui::Dataspace::TRANSFER_LINEAR`, 20.`ui::Dataspace::TRANSFER_SRGB`, 21.`ui::Dataspace::TRANSFER_SMPTE_170M`, 22.`ui::Dataspace::TRANSFER_GAMMA2_2`, 23.`ui::Dataspace::TRANSFER_GAMMA2_6`, 24.`ui::Dataspace::TRANSFER_GAMMA2_8`, 25.`ui::Dataspace::TRANSFER_ST2084`, 26.`ui::Dataspace::TRANSFER_HLG`, 27.`ui::Dataspace::RANGE_SHIFT`, 28.`ui::Dataspace::RANGE_MASK`, 29.`ui::Dataspace::RANGE_UNSPECIFIED`, 30.`ui::Dataspace::RANGE_FULL`, 31.`ui::Dataspace::RANGE_LIMITED`, 32.`ui::Dataspace::RANGE_EXTENDED`, 33.`ui::Dataspace::SRGB_LINEAR`, 34.`ui::Dataspace::V0_SRGB_LINEAR`, 35.`ui::Dataspace::V0_SCRGB_LINEAR`, 36.`ui::Dataspace::SRGB`, 37.`ui::Dataspace::V0_SRGB`, 38.`ui::Dataspace::V0_SCRGB`, 39.`ui::Dataspace::JFIF`, 40.`ui::Dataspace::V0_JFIF`, 41.`ui::Dataspace::BT601_625`, 42.`ui::Dataspace::V0_BT601_625`, 43.`ui::Dataspace::BT601_525`, 44.`ui::Dataspace::V0_BT601_525`, 45.`ui::Dataspace::BT709`, 46.`ui::Dataspace::V0_BT709`, 47.`ui::Dataspace::DCI_P3_LINEAR`, 48.`ui::Dataspace::DCI_P3`, 49.`ui::Dataspace::DISPLAY_P3_LINEAR`, 50.`ui::Dataspace::DISPLAY_P3`, 51.`ui::Dataspace::ADOBE_RGB`, 52.`ui::Dataspace::BT2020_LINEAR`, 53.`ui::Dataspace::BT2020`, 54.`ui::Dataspace::BT2020_PQ`, 55.`ui::Dataspace::DEPTH`, 56.`ui::Dataspace::SENSOR`, 57.`ui::Dataspace::BT2020_ITU`, 58.`ui::Dataspace::BT2020_ITU_PQ`, 59.`ui::Dataspace::BT2020_ITU_HLG`, 60.`ui::Dataspace::BT2020_HLG`, 61.`ui::Dataspace::DISPLAY_BT2020`, 62.`ui::Dataspace::DYNAMIC_DEPTH`, 63.`ui::Dataspace::JPEG_APP_SEGMENTS`, 64.`ui::Dataspace::HEIF`, |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) libgui_bufferQueue_fuzzer
+```
+2. To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/libgui_bufferQueue_fuzzer/libgui_bufferQueue_fuzzer
+```
+
+# <a name="libgui_consumer_fuzzer"></a> Fuzzer for Libgui_Consumer
+
+Libgui_Consumer supports the following parameters:
+1. GraphicWidth (parameter name:`graphicWidth`)
+2. GraphicHeight (parameter name:`graphicHeight`)
+4. TransformHint (parameter name:`outTransformHint`)
+5. GraphicPixelFormat (parameter name:`format`)
+6. Usage (parameter name:`usage`)
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) libgui_consumer_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/libgui_consumer_fuzzer/libgui_consumer_fuzzer
+```
+
+# <a name="libgui_displayEvent_fuzzer"></a> Fuzzer for LibGui_DisplayEvent
+
+LibGui_DisplayEvent supports the following parameters:
+1. DisplayEventType (parameter name:`type`)
+2. Events (parameter name:`events`)
+3. VsyncSource (parameter name:`vsyncSource`)
+4. EventRegistrationFlags (parameter name:`flags`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`vsyncSource`| 0.`ISurfaceComposer::eVsyncSourceApp`, 1.`ISurfaceComposer::eVsyncSourceSurfaceFlinger`, |Value obtained from FuzzedDataProvider|
+|`flags`| 0.`ISurfaceComposer::EventRegistration::modeChanged`, 1.`ISurfaceComposer::EventRegistration::frameRateOverride`, |Value obtained from FuzzedDataProvider|
+|`type`| 0.`DisplayEventReceiver::DISPLAY_EVENT_NULL`, 1.`DisplayEventReceiver::DISPLAY_EVENT_VSYNC`, 2.`DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG`, 3.`DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE`, 4.`DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE`, 5.`DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH`, |Value obtained from FuzzedDataProvider|
+|`events`| 0.`Looper::EVENT_INPUT`, 1.`Looper::EVENT_OUTPUT`, 2.`Looper::EVENT_ERROR`, 3.`Looper::EVENT_HANGUP`, 4.`Looper::EVENT_INVALID`, |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) libgui_displayEvent_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/libgui_displayEvent_fuzzer/libgui_displayEvent_fuzzer
+```
diff --git a/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp b/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
new file mode 100644
index 0000000..c97770b
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_bufferQueue_fuzzer.cpp
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2022 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 <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <system/window.h>
+
+#include <libgui_fuzzer_utils.h>
+
+using namespace android;
+using namespace hardware::graphics::bufferqueue;
+using namespace V1_0::utils;
+using namespace V2_0::utils;
+
+constexpr int32_t kMaxBytes = 256;
+
+constexpr int32_t kError[] = {
+ OK, NO_MEMORY, NO_INIT, BAD_VALUE, DEAD_OBJECT, INVALID_OPERATION,
+ TIMED_OUT, WOULD_BLOCK, UNKNOWN_ERROR, ALREADY_EXISTS,
+};
+
+constexpr int32_t kAPIConnection[] = {
+ BufferQueueCore::CURRENTLY_CONNECTED_API,
+ BufferQueueCore::NO_CONNECTED_API,
+ NATIVE_WINDOW_API_EGL,
+ NATIVE_WINDOW_API_CPU,
+ NATIVE_WINDOW_API_MEDIA,
+ NATIVE_WINDOW_API_CAMERA,
+};
+
+class BufferQueueFuzzer {
+public:
+ BufferQueueFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void process();
+
+private:
+ void invokeTypes();
+ void invokeH2BGraphicBufferV1();
+ void invokeH2BGraphicBufferV2();
+ void invokeBufferQueueConsumer();
+ void invokeBufferQueueProducer();
+ void invokeBlastBufferQueue();
+ void invokeQuery(sp<BufferQueueProducer>);
+ void invokeQuery(sp<V1_0::utils::H2BGraphicBufferProducer>);
+ void invokeQuery(sp<V2_0::utils::H2BGraphicBufferProducer>);
+ void invokeAcquireBuffer(sp<BufferQueueConsumer>);
+ void invokeOccupancyTracker(sp<BufferQueueConsumer>);
+ sp<SurfaceControl> makeSurfaceControl();
+ sp<BLASTBufferQueue> makeBLASTBufferQueue(sp<SurfaceControl>);
+
+ FuzzedDataProvider mFdp;
+};
+
+class ManageResourceHandle {
+public:
+ ManageResourceHandle(FuzzedDataProvider* fdp) {
+ mNativeHandle = native_handle_create(0 /*numFds*/, 1 /*numInts*/);
+ mShouldOwn = fdp->ConsumeBool();
+ mStream = NativeHandle::create(mNativeHandle, mShouldOwn);
+ }
+ ~ManageResourceHandle() {
+ if (!mShouldOwn) {
+ native_handle_close(mNativeHandle);
+ native_handle_delete(mNativeHandle);
+ }
+ }
+ sp<NativeHandle> getStream() { return mStream; }
+
+private:
+ bool mShouldOwn;
+ sp<NativeHandle> mStream;
+ native_handle_t* mNativeHandle;
+};
+
+sp<SurfaceControl> BufferQueueFuzzer::makeSurfaceControl() {
+ sp<IBinder> handle;
+ const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient());
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient);
+ sp<BnGraphicBufferProducer> producer;
+ return sp<SurfaceControl>::make(client, handle, mFdp.ConsumeIntegral<int32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<int32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>());
+}
+
+sp<BLASTBufferQueue> BufferQueueFuzzer::makeBLASTBufferQueue(sp<SurfaceControl> surface) {
+ return sp<BLASTBufferQueue>::make(mFdp.ConsumeRandomLengthString(kMaxBytes), surface,
+ mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<int32_t>());
+}
+
+void BufferQueueFuzzer::invokeBlastBufferQueue() {
+ sp<SurfaceControl> surface = makeSurfaceControl();
+ sp<BLASTBufferQueue> queue = makeBLASTBufferQueue(surface);
+
+ BufferItem item;
+ queue->onFrameAvailable(item);
+ queue->onFrameReplaced(item);
+ uint64_t bufferId = mFdp.ConsumeIntegral<uint64_t>();
+ queue->onFrameDequeued(bufferId);
+ queue->onFrameCancelled(bufferId);
+
+ SurfaceComposerClient::Transaction next;
+ uint64_t frameNumber = mFdp.ConsumeIntegral<uint64_t>();
+ queue->mergeWithNextTransaction(&next, frameNumber);
+ queue->applyPendingTransactions(frameNumber);
+
+ queue->update(surface, mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<int32_t>());
+ queue->setFrameRate(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeIntegral<int8_t>(),
+ mFdp.ConsumeBool() /*shouldBeSeamless*/);
+ FrameTimelineInfo info;
+ queue->setFrameTimelineInfo(info);
+
+ ManageResourceHandle handle(&mFdp);
+ queue->setSidebandStream(handle.getStream());
+
+ queue->getLastTransformHint();
+ queue->getLastAcquiredFrameNum();
+
+ CompositorTiming compTiming;
+ sp<Fence> previousFence = new Fence(memfd_create("pfd", MFD_ALLOW_SEALING));
+ sp<Fence> gpuFence = new Fence(memfd_create("gfd", MFD_ALLOW_SEALING));
+ FrameEventHistoryStats frameStats(frameNumber, gpuFence, compTiming,
+ mFdp.ConsumeIntegral<int64_t>(),
+ mFdp.ConsumeIntegral<int64_t>());
+ std::vector<SurfaceControlStats> stats;
+ sp<Fence> presentFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
+ SurfaceControlStats controlStats(surface, mFdp.ConsumeIntegral<int64_t>(),
+ mFdp.ConsumeIntegral<int64_t>(), presentFence, previousFence,
+ mFdp.ConsumeIntegral<uint32_t>(), frameStats);
+ stats.push_back(controlStats);
+}
+
+void BufferQueueFuzzer::invokeQuery(sp<BufferQueueProducer> producer) {
+ int32_t value;
+ producer->query(mFdp.ConsumeIntegral<int32_t>(), &value);
+}
+
+void BufferQueueFuzzer::invokeQuery(sp<V1_0::utils::H2BGraphicBufferProducer> producer) {
+ int32_t value;
+ producer->query(mFdp.ConsumeIntegral<int32_t>(), &value);
+}
+
+void BufferQueueFuzzer::invokeQuery(sp<V2_0::utils::H2BGraphicBufferProducer> producer) {
+ int32_t value;
+ producer->query(mFdp.ConsumeIntegral<int32_t>(), &value);
+}
+
+void BufferQueueFuzzer::invokeBufferQueueProducer() {
+ sp<BufferQueueCore> core(new BufferQueueCore());
+ sp<BufferQueueProducer> producer(new BufferQueueProducer(core));
+ const sp<android::IProducerListener> listener;
+ android::IGraphicBufferProducer::QueueBufferOutput output;
+ uint32_t api = mFdp.ConsumeIntegral<uint32_t>();
+ producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output);
+
+ sp<GraphicBuffer> buffer;
+ int32_t slot = mFdp.ConsumeIntegral<int32_t>();
+ uint32_t maxBuffers = mFdp.ConsumeIntegral<uint32_t>();
+ producer->requestBuffer(slot, &buffer);
+ producer->setMaxDequeuedBufferCount(maxBuffers);
+ producer->setAsyncMode(mFdp.ConsumeBool() /*async*/);
+
+ android::IGraphicBufferProducer::QueueBufferInput input;
+ producer->attachBuffer(&slot, buffer);
+ producer->queueBuffer(slot, input, &output);
+
+ int32_t format = mFdp.ConsumeIntegral<int32_t>();
+ uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+ uint64_t usage = mFdp.ConsumeIntegral<uint64_t>();
+ uint64_t outBufferAge;
+ FrameEventHistoryDelta outTimestamps;
+ sp<android::Fence> fence;
+ producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge,
+ &outTimestamps);
+ producer->detachBuffer(slot);
+ producer->detachNextBuffer(&buffer, &fence);
+ producer->cancelBuffer(slot, fence);
+
+ invokeQuery(producer);
+
+ ManageResourceHandle handle(&mFdp);
+ producer->setSidebandStream(handle.getStream());
+
+ producer->allocateBuffers(width, height, format, usage);
+ producer->allowAllocation(mFdp.ConsumeBool() /*allow*/);
+ producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/);
+ producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/);
+ producer->setLegacyBufferDrop(mFdp.ConsumeBool() /*drop*/);
+ producer->setAutoPrerotation(mFdp.ConsumeBool() /*autoPrerotation*/);
+
+ producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>());
+ producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>());
+ producer->disconnect(api);
+}
+
+void BufferQueueFuzzer::invokeAcquireBuffer(sp<BufferQueueConsumer> consumer) {
+ BufferItem item;
+ consumer->acquireBuffer(&item, mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint64_t>());
+}
+
+void BufferQueueFuzzer::invokeOccupancyTracker(sp<BufferQueueConsumer> consumer) {
+ String8 outResult;
+ String8 prefix((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
+ consumer->dumpState(prefix, &outResult);
+
+ std::vector<OccupancyTracker::Segment> outHistory;
+ consumer->getOccupancyHistory(mFdp.ConsumeBool() /*forceFlush*/, &outHistory);
+}
+
+void BufferQueueFuzzer::invokeBufferQueueConsumer() {
+ sp<BufferQueueCore> core(new BufferQueueCore());
+ sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
+ sp<android::IConsumerListener> listener;
+ consumer->consumerConnect(listener, mFdp.ConsumeBool() /*controlledByApp*/);
+ invokeAcquireBuffer(consumer);
+
+ int32_t slot = mFdp.ConsumeIntegral<int32_t>();
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint64_t>());
+ consumer->attachBuffer(&slot, buffer);
+ consumer->detachBuffer(slot);
+
+ consumer->setDefaultBufferSize(mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>());
+ consumer->setMaxBufferCount(mFdp.ConsumeIntegral<int32_t>());
+ consumer->setMaxAcquiredBufferCount(mFdp.ConsumeIntegral<int32_t>());
+
+ String8 name((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
+ consumer->setConsumerName(name);
+ consumer->setDefaultBufferFormat(mFdp.ConsumeIntegral<int32_t>());
+ android_dataspace dataspace =
+ static_cast<android_dataspace>(mFdp.PickValueInArray(kDataspaces));
+ consumer->setDefaultBufferDataSpace(dataspace);
+
+ consumer->setTransformHint(mFdp.ConsumeIntegral<uint32_t>());
+ consumer->setConsumerUsageBits(mFdp.ConsumeIntegral<uint64_t>());
+ consumer->setConsumerIsProtected(mFdp.ConsumeBool() /*isProtected*/);
+ invokeOccupancyTracker(consumer);
+
+ sp<Fence> releaseFence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
+ consumer->releaseBuffer(mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint64_t>(),
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence);
+ consumer->consumerDisconnect();
+}
+
+void BufferQueueFuzzer::invokeTypes() {
+ HStatus hStatus;
+ int32_t status = mFdp.PickValueInArray(kError);
+ bool bufferNeedsReallocation = mFdp.ConsumeBool();
+ bool releaseAllBuffers = mFdp.ConsumeBool();
+ b2h(status, &hStatus, &bufferNeedsReallocation, &releaseAllBuffers);
+ h2b(hStatus, &status);
+
+ HConnectionType type;
+ int32_t apiConnection = mFdp.PickValueInArray(kAPIConnection);
+ b2h(apiConnection, &type);
+ h2b(type, &apiConnection);
+}
+
+void BufferQueueFuzzer::invokeH2BGraphicBufferV1() {
+ sp<V1_0::utils::H2BGraphicBufferProducer> producer(
+ new V1_0::utils::H2BGraphicBufferProducer(new FakeGraphicBufferProducerV1()));
+ const sp<android::IProducerListener> listener;
+ android::IGraphicBufferProducer::QueueBufferOutput output;
+ uint32_t api = mFdp.ConsumeIntegral<uint32_t>();
+ producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output);
+
+ sp<GraphicBuffer> buffer;
+ int32_t slot = mFdp.ConsumeIntegral<int32_t>();
+ producer->requestBuffer(slot, &buffer);
+ producer->setMaxDequeuedBufferCount(mFdp.ConsumeIntegral<int32_t>());
+ producer->setAsyncMode(mFdp.ConsumeBool());
+
+ android::IGraphicBufferProducer::QueueBufferInput input;
+ input.fence = new Fence(memfd_create("ffd", MFD_ALLOW_SEALING));
+ producer->attachBuffer(&slot, buffer);
+ producer->queueBuffer(slot, input, &output);
+
+ int32_t format = mFdp.ConsumeIntegral<int32_t>();
+ uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+ uint64_t usage = mFdp.ConsumeIntegral<uint64_t>();
+ uint64_t outBufferAge;
+ FrameEventHistoryDelta outTimestamps;
+ sp<android::Fence> fence;
+ producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge,
+ &outTimestamps);
+ producer->detachBuffer(slot);
+ producer->cancelBuffer(slot, fence);
+
+ invokeQuery(producer);
+
+ ManageResourceHandle handle(&mFdp);
+ producer->setSidebandStream(handle.getStream());
+
+ producer->allocateBuffers(width, height, format, usage);
+ producer->allowAllocation(mFdp.ConsumeBool() /*allow*/);
+ producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/);
+ producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/);
+
+ producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>());
+ producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>());
+ producer->disconnect(api);
+}
+
+void BufferQueueFuzzer::invokeH2BGraphicBufferV2() {
+ sp<V2_0::utils::H2BGraphicBufferProducer> producer(
+ new V2_0::utils::H2BGraphicBufferProducer(new FakeGraphicBufferProducerV2()));
+ const sp<android::IProducerListener> listener;
+ android::IGraphicBufferProducer::QueueBufferOutput output;
+ uint32_t api = mFdp.ConsumeIntegral<uint32_t>();
+ producer->connect(listener, api, mFdp.ConsumeBool() /*producerControlledByApp*/, &output);
+
+ sp<GraphicBuffer> buffer;
+ int32_t slot = mFdp.ConsumeIntegral<int32_t>();
+ producer->requestBuffer(slot, &buffer);
+ producer->setMaxDequeuedBufferCount(mFdp.ConsumeIntegral<uint32_t>());
+ producer->setAsyncMode(mFdp.ConsumeBool());
+
+ android::IGraphicBufferProducer::QueueBufferInput input;
+ input.fence = new Fence(memfd_create("ffd", MFD_ALLOW_SEALING));
+ producer->attachBuffer(&slot, buffer);
+ producer->queueBuffer(slot, input, &output);
+
+ int32_t format = mFdp.ConsumeIntegral<int32_t>();
+ uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+ uint64_t usage = mFdp.ConsumeIntegral<uint64_t>();
+ uint64_t outBufferAge;
+ FrameEventHistoryDelta outTimestamps;
+ sp<android::Fence> fence;
+ producer->dequeueBuffer(&slot, &fence, width, height, format, usage, &outBufferAge,
+ &outTimestamps);
+ producer->detachBuffer(slot);
+ producer->cancelBuffer(slot, fence);
+
+ invokeQuery(producer);
+
+ ManageResourceHandle handle(&mFdp);
+ producer->setSidebandStream(handle.getStream());
+
+ producer->allocateBuffers(width, height, format, usage);
+ producer->allowAllocation(mFdp.ConsumeBool() /*allow*/);
+ producer->setSharedBufferMode(mFdp.ConsumeBool() /*sharedBufferMode*/);
+ producer->setAutoRefresh(mFdp.ConsumeBool() /*autoRefresh*/);
+
+ producer->setGenerationNumber(mFdp.ConsumeIntegral<uint32_t>());
+ producer->setDequeueTimeout(mFdp.ConsumeIntegral<uint32_t>());
+ producer->disconnect(api);
+}
+
+void BufferQueueFuzzer::process() {
+ invokeBlastBufferQueue();
+ invokeH2BGraphicBufferV1();
+ invokeH2BGraphicBufferV2();
+ invokeTypes();
+ invokeBufferQueueConsumer();
+ invokeBufferQueueProducer();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ BufferQueueFuzzer bufferQueueFuzzer(data, size);
+ bufferQueueFuzzer.process();
+ return 0;
+}
diff --git a/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp b/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp
new file mode 100644
index 0000000..24a046d
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_consumer_fuzzer.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2022 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 <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/GLConsumer.h>
+#include <libgui_fuzzer_utils.h>
+
+using namespace android;
+
+constexpr int32_t kMinBuffer = 0;
+constexpr int32_t kMaxBuffer = 100000;
+
+class ConsumerFuzzer {
+public:
+ ConsumerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void process();
+
+private:
+ FuzzedDataProvider mFdp;
+};
+
+void ConsumerFuzzer::process() {
+ sp<BufferQueueCore> core(new BufferQueueCore());
+ sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
+
+ uint64_t maxBuffers = mFdp.ConsumeIntegralInRange<uint64_t>(kMinBuffer, kMaxBuffer);
+ sp<CpuConsumer> cpu(
+ new CpuConsumer(consumer, maxBuffers, mFdp.ConsumeBool() /*controlledByApp*/));
+ CpuConsumer::LockedBuffer lockBuffer;
+ cpu->lockNextBuffer(&lockBuffer);
+ cpu->unlockBuffer(lockBuffer);
+ cpu->abandon();
+
+ uint32_t tex = mFdp.ConsumeIntegral<uint32_t>();
+ sp<GLConsumer> glComsumer(new GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL,
+ mFdp.ConsumeBool() /*useFenceSync*/,
+ mFdp.ConsumeBool() /*isControlledByApp*/));
+ sp<Fence> releaseFence = new Fence(memfd_create("rfd", MFD_ALLOW_SEALING));
+ glComsumer->setReleaseFence(releaseFence);
+ glComsumer->updateTexImage();
+ glComsumer->releaseTexImage();
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<int32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint64_t>());
+ float mtx[16];
+ glComsumer->getTransformMatrix(mtx);
+ glComsumer->computeTransformMatrix(mtx, buffer, getRect(&mFdp),
+ mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeBool() /*filtering*/);
+ glComsumer->scaleDownCrop(getRect(&mFdp), mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>());
+
+ glComsumer->setDefaultBufferSize(mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>());
+ glComsumer->setFilteringEnabled(mFdp.ConsumeBool() /*enabled*/);
+
+ glComsumer->setConsumerUsageBits(mFdp.ConsumeIntegral<uint64_t>());
+ glComsumer->attachToContext(tex);
+ glComsumer->abandon();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ ConsumerFuzzer consumerFuzzer(data, size);
+ consumerFuzzer.process();
+ return 0;
+}
diff --git a/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp b/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp
new file mode 100644
index 0000000..6d5ae49
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_displayEvent_fuzzer.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/gui/ISurfaceComposer.h>
+
+#include <libgui_fuzzer_utils.h>
+
+using namespace android;
+
+constexpr gui::ISurfaceComposer::VsyncSource kVsyncSource[] = {
+ gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp,
+ gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger,
+};
+
+constexpr gui::ISurfaceComposer::EventRegistration kEventRegistration[] = {
+ gui::ISurfaceComposer::EventRegistration::modeChanged,
+ gui::ISurfaceComposer::EventRegistration::frameRateOverride,
+};
+
+constexpr uint32_t kDisplayEvent[] = {
+ DisplayEventReceiver::DISPLAY_EVENT_NULL,
+ DisplayEventReceiver::DISPLAY_EVENT_VSYNC,
+ DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
+ DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE,
+ DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
+ DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH,
+};
+
+constexpr int32_t kEvents[] = {
+ Looper::EVENT_INPUT, Looper::EVENT_OUTPUT, Looper::EVENT_ERROR,
+ Looper::EVENT_HANGUP, Looper::EVENT_INVALID,
+};
+
+DisplayEventReceiver::Event buildDisplayEvent(FuzzedDataProvider* fdp, uint32_t type,
+ DisplayEventReceiver::Event event) {
+ switch (type) {
+ case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: {
+ event.vsync.count = fdp->ConsumeIntegral<uint32_t>();
+ event.vsync.vsyncData.frameInterval = fdp->ConsumeIntegral<uint64_t>();
+ event.vsync.vsyncData.preferredFrameTimelineIndex = fdp->ConsumeIntegral<uint32_t>();
+ for (size_t idx = 0; idx < gui::VsyncEventData::kFrameTimelinesLength; ++idx) {
+ event.vsync.vsyncData.frameTimelines[idx].vsyncId = fdp->ConsumeIntegral<int64_t>();
+ event.vsync.vsyncData.frameTimelines[idx].deadlineTimestamp =
+ fdp->ConsumeIntegral<uint64_t>();
+ event.vsync.vsyncData.frameTimelines[idx].expectedPresentationTime =
+ fdp->ConsumeIntegral<uint64_t>();
+ }
+ break;
+
+ }
+ case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: {
+ event.hotplug = DisplayEventReceiver::Event::Hotplug{fdp->ConsumeBool() /*connected*/};
+ break;
+ }
+ case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: {
+ event.modeChange =
+ DisplayEventReceiver::Event::ModeChange{fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int64_t>()};
+ break;
+ }
+ case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
+ case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH: {
+ event.frameRateOverride =
+ DisplayEventReceiver::Event::FrameRateOverride{fdp->ConsumeIntegral<uint32_t>(),
+ fdp->ConsumeFloatingPoint<
+ float>()};
+ break;
+ }
+ }
+ return event;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ sp<Looper> looper;
+ sp<FakeDisplayEventDispatcher> dispatcher(
+ new FakeDisplayEventDispatcher(looper, fdp.PickValueInArray(kVsyncSource),
+ fdp.PickValueInArray(kEventRegistration)));
+
+ dispatcher->initialize();
+ DisplayEventReceiver::Event event;
+ uint32_t type = fdp.PickValueInArray(kDisplayEvent);
+ PhysicalDisplayId displayId;
+ event.header =
+ DisplayEventReceiver::Event::Header{type, displayId, fdp.ConsumeIntegral<int64_t>()};
+ event = buildDisplayEvent(&fdp, type, event);
+
+ dispatcher->injectEvent(event);
+ dispatcher->handleEvent(0, fdp.PickValueInArray(kEvents), nullptr);
+ return 0;
+}
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
index 98e2ea3..d51f685 100644
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -71,7 +71,6 @@
(override));
MOCK_METHOD(binder::Status, destroyDisplay, (const sp<IBinder>&), (override));
MOCK_METHOD(binder::Status, getPhysicalDisplayIds, (std::vector<int64_t>*), (override));
- MOCK_METHOD(binder::Status, getPrimaryPhysicalDisplayId, (int64_t*), (override));
MOCK_METHOD(binder::Status, getPhysicalDisplayToken, (int64_t, sp<IBinder>*), (override));
MOCK_METHOD(binder::Status, setPowerMode, (const sp<IBinder>&, int), (override));
MOCK_METHOD(binder::Status, getSupportedFrameTimestamps, (std::vector<FrameEvent>*),
@@ -174,6 +173,9 @@
MOCK_METHOD(binder::Status, mirrorSurface,
(const sp<IBinder>& mirrorFromHandle, gui::MirrorSurfaceResult* outResult),
(override));
+
+ MOCK_METHOD(binder::Status, mirrorDisplay,
+ (int64_t displayId, gui::MirrorSurfaceResult* outResult), (override));
};
class FakeDisplayEventDispatcher : public DisplayEventDispatcher {
diff --git a/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp b/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp
new file mode 100644
index 0000000..9f0f6ca
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_parcelable_fuzzer.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2022 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 <gui/BufferQueueConsumer.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
+#include <gui/LayerMetadata.h>
+#include <gui/OccupancyTracker.h>
+#include <gui/StreamSplitter.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceControl.h>
+#include <gui/view/Surface.h>
+#include <libgui_fuzzer_utils.h>
+#include "android/view/LayerMetadataKey.h"
+
+using namespace android;
+
+constexpr int32_t kMaxBytes = 256;
+constexpr int32_t kMatrixSize = 4;
+constexpr int32_t kLayerMetadataKeyCount = 8;
+
+constexpr uint32_t kMetadataKey[] = {
+ (uint32_t)view::LayerMetadataKey::METADATA_OWNER_UID,
+ (uint32_t)view::LayerMetadataKey::METADATA_WINDOW_TYPE,
+ (uint32_t)view::LayerMetadataKey::METADATA_TASK_ID,
+ (uint32_t)view::LayerMetadataKey::METADATA_MOUSE_CURSOR,
+ (uint32_t)view::LayerMetadataKey::METADATA_ACCESSIBILITY_ID,
+ (uint32_t)view::LayerMetadataKey::METADATA_OWNER_PID,
+ (uint32_t)view::LayerMetadataKey::METADATA_DEQUEUE_TIME,
+ (uint32_t)view::LayerMetadataKey::METADATA_GAME_MODE,
+};
+
+class ParcelableFuzzer {
+public:
+ ParcelableFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void process();
+
+private:
+ void invokeStreamSplitter();
+ void invokeOccupancyTracker();
+ void invokeLayerDebugInfo();
+ void invokeLayerMetadata();
+ void invokeViewSurface();
+
+ FuzzedDataProvider mFdp;
+};
+
+void ParcelableFuzzer::invokeViewSurface() {
+ view::Surface surface;
+ surface.name = String16((mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
+ Parcel parcel;
+ surface.writeToParcel(&parcel);
+ parcel.setDataPosition(0);
+ surface.readFromParcel(&parcel);
+ bool nameAlreadyWritten = mFdp.ConsumeBool();
+ surface.writeToParcel(&parcel, nameAlreadyWritten);
+ parcel.setDataPosition(0);
+ surface.readFromParcel(&parcel, mFdp.ConsumeBool());
+}
+
+void ParcelableFuzzer::invokeLayerMetadata() {
+ std::unordered_map<uint32_t, std::vector<uint8_t>> map;
+ for (size_t idx = 0; idx < kLayerMetadataKeyCount; ++idx) {
+ std::vector<uint8_t> data;
+ for (size_t idx1 = 0; idx1 < mFdp.ConsumeIntegral<uint32_t>(); ++idx1) {
+ data.push_back(mFdp.ConsumeIntegral<uint8_t>());
+ }
+ map[kMetadataKey[idx]] = data;
+ }
+ LayerMetadata metadata(map);
+ uint32_t key = mFdp.PickValueInArray(kMetadataKey);
+ metadata.setInt32(key, mFdp.ConsumeIntegral<int32_t>());
+ metadata.itemToString(key, (mFdp.ConsumeRandomLengthString(kMaxBytes)).c_str());
+
+ Parcel parcel;
+ metadata.writeToParcel(&parcel);
+ parcel.setDataPosition(0);
+ metadata.readFromParcel(&parcel);
+}
+
+void ParcelableFuzzer::invokeLayerDebugInfo() {
+ gui::LayerDebugInfo info;
+ info.mName = mFdp.ConsumeRandomLengthString(kMaxBytes);
+ info.mParentName = mFdp.ConsumeRandomLengthString(kMaxBytes);
+ info.mType = mFdp.ConsumeRandomLengthString(kMaxBytes);
+ info.mLayerStack = mFdp.ConsumeIntegral<uint32_t>();
+ info.mX = mFdp.ConsumeFloatingPoint<float>();
+ info.mY = mFdp.ConsumeFloatingPoint<float>();
+ info.mZ = mFdp.ConsumeIntegral<uint32_t>();
+ info.mWidth = mFdp.ConsumeIntegral<int32_t>();
+ info.mHeight = mFdp.ConsumeIntegral<int32_t>();
+ info.mActiveBufferWidth = mFdp.ConsumeIntegral<int32_t>();
+ info.mActiveBufferHeight = mFdp.ConsumeIntegral<int32_t>();
+ info.mActiveBufferStride = mFdp.ConsumeIntegral<int32_t>();
+ info.mActiveBufferFormat = mFdp.ConsumeIntegral<int32_t>();
+ info.mNumQueuedFrames = mFdp.ConsumeIntegral<int32_t>();
+
+ info.mFlags = mFdp.ConsumeIntegral<uint32_t>();
+ info.mPixelFormat = mFdp.ConsumeIntegral<int32_t>();
+ info.mTransparentRegion = Region(getRect(&mFdp));
+ info.mVisibleRegion = Region(getRect(&mFdp));
+ info.mSurfaceDamageRegion = Region(getRect(&mFdp));
+ info.mCrop = getRect(&mFdp);
+ info.mDataSpace = static_cast<android_dataspace>(mFdp.PickValueInArray(kDataspaces));
+ info.mColor = half4(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>());
+ for (size_t idx = 0; idx < kMatrixSize; ++idx) {
+ info.mMatrix[idx / 2][idx % 2] = mFdp.ConsumeFloatingPoint<float>();
+ }
+ info.mIsOpaque = mFdp.ConsumeBool();
+ info.mContentDirty = mFdp.ConsumeBool();
+ info.mStretchEffect.width = mFdp.ConsumeFloatingPoint<float>();
+ info.mStretchEffect.height = mFdp.ConsumeFloatingPoint<float>();
+ info.mStretchEffect.vectorX = mFdp.ConsumeFloatingPoint<float>();
+ info.mStretchEffect.vectorY = mFdp.ConsumeFloatingPoint<float>();
+ info.mStretchEffect.maxAmountX = mFdp.ConsumeFloatingPoint<float>();
+ info.mStretchEffect.maxAmountY = mFdp.ConsumeFloatingPoint<float>();
+ info.mStretchEffect.mappedChildBounds =
+ FloatRect(mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(), mFdp.ConsumeFloatingPoint<float>());
+
+ Parcel parcel;
+ info.writeToParcel(&parcel);
+ parcel.setDataPosition(0);
+ info.readFromParcel(&parcel);
+}
+
+void ParcelableFuzzer::invokeOccupancyTracker() {
+ nsecs_t totalTime = mFdp.ConsumeIntegral<uint32_t>();
+ size_t numFrames = mFdp.ConsumeIntegral<size_t>();
+ float occupancyAverage = mFdp.ConsumeFloatingPoint<float>();
+ OccupancyTracker::Segment segment(totalTime, numFrames, occupancyAverage,
+ mFdp.ConsumeBool() /*usedThirdBuffer*/);
+ Parcel parcel;
+ segment.writeToParcel(&parcel);
+ parcel.setDataPosition(0);
+ segment.readFromParcel(&parcel);
+}
+
+void ParcelableFuzzer::invokeStreamSplitter() {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ sp<StreamSplitter> splitter;
+ StreamSplitter::createSplitter(consumer, &splitter);
+ splitter->addOutput(producer);
+ std::string name = mFdp.ConsumeRandomLengthString(kMaxBytes);
+ splitter->setName(String8(name.c_str()));
+}
+
+void ParcelableFuzzer::process() {
+ invokeStreamSplitter();
+ invokeOccupancyTracker();
+ invokeLayerDebugInfo();
+ invokeLayerMetadata();
+ invokeViewSurface();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ ParcelableFuzzer libGuiFuzzer(data, size);
+ libGuiFuzzer.process();
+ return 0;
+}
diff --git a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
new file mode 100644
index 0000000..05564e0
--- /dev/null
+++ b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android/hardware/power/Boost.h>
+#include <fuzzbinder/libbinder_driver.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <libgui_fuzzer_utils.h>
+
+using namespace android;
+
+constexpr int32_t kRandomStringMaxBytes = 256;
+
+constexpr ui::ColorMode kColormodes[] = {ui::ColorMode::NATIVE,
+ ui::ColorMode::STANDARD_BT601_625,
+ ui::ColorMode::STANDARD_BT601_625_UNADJUSTED,
+ ui::ColorMode::STANDARD_BT601_525,
+ ui::ColorMode::STANDARD_BT601_525_UNADJUSTED,
+ ui::ColorMode::STANDARD_BT709,
+ ui::ColorMode::DCI_P3,
+ ui::ColorMode::SRGB,
+ ui::ColorMode::ADOBE_RGB,
+ ui::ColorMode::DISPLAY_P3,
+ ui::ColorMode::BT2020,
+ ui::ColorMode::BT2100_PQ,
+ ui::ColorMode::BT2100_HLG,
+ ui::ColorMode::DISPLAY_BT2020};
+
+constexpr hardware::power::Boost kBoost[] = {
+ hardware::power::Boost::INTERACTION, hardware::power::Boost::DISPLAY_UPDATE_IMMINENT,
+ hardware::power::Boost::ML_ACC, hardware::power::Boost::AUDIO_LAUNCH,
+ hardware::power::Boost::CAMERA_LAUNCH, hardware::power::Boost::CAMERA_SHOT,
+};
+
+constexpr gui::TouchOcclusionMode kMode[] = {
+ gui::TouchOcclusionMode::BLOCK_UNTRUSTED,
+ gui::TouchOcclusionMode::USE_OPACITY,
+ gui::TouchOcclusionMode::ALLOW,
+};
+
+constexpr gui::WindowInfo::Flag kFlags[] = {
+ gui::WindowInfo::Flag::ALLOW_LOCK_WHILE_SCREEN_ON,
+ gui::WindowInfo::Flag::DIM_BEHIND,
+ gui::WindowInfo::Flag::BLUR_BEHIND,
+ gui::WindowInfo::Flag::NOT_FOCUSABLE,
+ gui::WindowInfo::Flag::NOT_TOUCHABLE,
+ gui::WindowInfo::Flag::NOT_TOUCH_MODAL,
+ gui::WindowInfo::Flag::TOUCHABLE_WHEN_WAKING,
+ gui::WindowInfo::Flag::KEEP_SCREEN_ON,
+ gui::WindowInfo::Flag::LAYOUT_IN_SCREEN,
+ gui::WindowInfo::Flag::LAYOUT_NO_LIMITS,
+ gui::WindowInfo::Flag::FULLSCREEN,
+ gui::WindowInfo::Flag::FORCE_NOT_FULLSCREEN,
+ gui::WindowInfo::Flag::DITHER,
+ gui::WindowInfo::Flag::SECURE,
+ gui::WindowInfo::Flag::SCALED,
+ gui::WindowInfo::Flag::IGNORE_CHEEK_PRESSES,
+ gui::WindowInfo::Flag::LAYOUT_INSET_DECOR,
+ gui::WindowInfo::Flag::ALT_FOCUSABLE_IM,
+ gui::WindowInfo::Flag::WATCH_OUTSIDE_TOUCH,
+ gui::WindowInfo::Flag::SHOW_WHEN_LOCKED,
+ gui::WindowInfo::Flag::SHOW_WALLPAPER,
+ gui::WindowInfo::Flag::TURN_SCREEN_ON,
+ gui::WindowInfo::Flag::DISMISS_KEYGUARD,
+ gui::WindowInfo::Flag::SPLIT_TOUCH,
+ gui::WindowInfo::Flag::HARDWARE_ACCELERATED,
+ gui::WindowInfo::Flag::LAYOUT_IN_OVERSCAN,
+ gui::WindowInfo::Flag::TRANSLUCENT_STATUS,
+ gui::WindowInfo::Flag::TRANSLUCENT_NAVIGATION,
+ gui::WindowInfo::Flag::LOCAL_FOCUS_MODE,
+ gui::WindowInfo::Flag::SLIPPERY,
+ gui::WindowInfo::Flag::LAYOUT_ATTACHED_IN_DECOR,
+ gui::WindowInfo::Flag::DRAWS_SYSTEM_BAR_BACKGROUNDS,
+};
+
+constexpr gui::WindowInfo::Type kType[] = {
+ gui::WindowInfo::Type::UNKNOWN,
+ gui::WindowInfo::Type::FIRST_APPLICATION_WINDOW,
+ gui::WindowInfo::Type::BASE_APPLICATION,
+ gui::WindowInfo::Type::APPLICATION,
+ gui::WindowInfo::Type::APPLICATION_STARTING,
+ gui::WindowInfo::Type::LAST_APPLICATION_WINDOW,
+ gui::WindowInfo::Type::FIRST_SUB_WINDOW,
+ gui::WindowInfo::Type::APPLICATION_PANEL,
+ gui::WindowInfo::Type::APPLICATION_MEDIA,
+ gui::WindowInfo::Type::APPLICATION_SUB_PANEL,
+ gui::WindowInfo::Type::APPLICATION_ATTACHED_DIALOG,
+ gui::WindowInfo::Type::APPLICATION_MEDIA_OVERLAY,
+};
+
+constexpr gui::WindowInfo::InputConfig kFeatures[] = {
+ gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL,
+ gui::WindowInfo::InputConfig::DISABLE_USER_ACTIVITY,
+ gui::WindowInfo::InputConfig::DROP_INPUT,
+ gui::WindowInfo::InputConfig::DROP_INPUT_IF_OBSCURED,
+ gui::WindowInfo::InputConfig::SPY,
+ gui::WindowInfo::InputConfig::INTERCEPTS_STYLUS,
+};
+
+class SurfaceComposerClientFuzzer {
+public:
+ SurfaceComposerClientFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void process();
+
+private:
+ void invokeSurfaceComposerClient();
+ void invokeSurfaceComposerClientBinder();
+ void invokeSurfaceComposerTransaction();
+ void getWindowInfo(gui::WindowInfo*);
+ sp<SurfaceControl> makeSurfaceControl();
+ BlurRegion getBlurRegion();
+ void fuzzOnPullAtom();
+
+ FuzzedDataProvider mFdp;
+};
+
+BlurRegion SurfaceComposerClientFuzzer::getBlurRegion() {
+ int32_t left = mFdp.ConsumeIntegral<int32_t>();
+ int32_t right = mFdp.ConsumeIntegral<int32_t>();
+ int32_t top = mFdp.ConsumeIntegral<int32_t>();
+ int32_t bottom = mFdp.ConsumeIntegral<int32_t>();
+ uint32_t blurRadius = mFdp.ConsumeIntegral<uint32_t>();
+ float alpha = mFdp.ConsumeFloatingPoint<float>();
+ float cornerRadiusTL = mFdp.ConsumeFloatingPoint<float>();
+ float cornerRadiusTR = mFdp.ConsumeFloatingPoint<float>();
+ float cornerRadiusBL = mFdp.ConsumeFloatingPoint<float>();
+ float cornerRadiusBR = mFdp.ConsumeFloatingPoint<float>();
+ return BlurRegion{blurRadius, cornerRadiusTL, cornerRadiusTR, cornerRadiusBL,
+ cornerRadiusBR, alpha, left, top,
+ right, bottom};
+}
+
+void SurfaceComposerClientFuzzer::getWindowInfo(gui::WindowInfo* windowInfo) {
+ windowInfo->id = mFdp.ConsumeIntegral<int32_t>();
+ windowInfo->name = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes);
+ windowInfo->layoutParamsFlags = mFdp.PickValueInArray(kFlags);
+ windowInfo->layoutParamsType = mFdp.PickValueInArray(kType);
+ windowInfo->frameLeft = mFdp.ConsumeIntegral<int32_t>();
+ windowInfo->frameTop = mFdp.ConsumeIntegral<int32_t>();
+ windowInfo->frameRight = mFdp.ConsumeIntegral<int32_t>();
+ windowInfo->frameBottom = mFdp.ConsumeIntegral<int32_t>();
+ windowInfo->surfaceInset = mFdp.ConsumeIntegral<int32_t>();
+ windowInfo->alpha = mFdp.ConsumeFloatingPointInRange<float>(0, 1);
+ ui::Transform transform(mFdp.PickValueInArray(kOrientation));
+ windowInfo->transform = transform;
+ windowInfo->touchableRegion = Region(getRect(&mFdp));
+ windowInfo->replaceTouchableRegionWithCrop = mFdp.ConsumeBool();
+ windowInfo->touchOcclusionMode = mFdp.PickValueInArray(kMode);
+ windowInfo->ownerPid = mFdp.ConsumeIntegral<int32_t>();
+ windowInfo->ownerUid = mFdp.ConsumeIntegral<int32_t>();
+ windowInfo->packageName = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes);
+ windowInfo->inputConfig = mFdp.PickValueInArray(kFeatures);
+}
+
+sp<SurfaceControl> SurfaceComposerClientFuzzer::makeSurfaceControl() {
+ sp<IBinder> handle;
+ const sp<FakeBnSurfaceComposerClient> testClient(new FakeBnSurfaceComposerClient());
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient(testClient);
+ sp<BnGraphicBufferProducer> producer;
+ uint32_t width = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t height = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t transformHint = mFdp.ConsumeIntegral<uint32_t>();
+ uint32_t flags = mFdp.ConsumeIntegral<uint32_t>();
+ int32_t format = mFdp.ConsumeIntegral<int32_t>();
+ int32_t layerId = mFdp.ConsumeIntegral<int32_t>();
+ return new SurfaceControl(client, handle, layerId, width, height, format, transformHint, flags);
+}
+
+void SurfaceComposerClientFuzzer::invokeSurfaceComposerTransaction() {
+ sp<SurfaceControl> surface = makeSurfaceControl();
+
+ SurfaceComposerClient::Transaction transaction;
+ transaction.setSize(surface, mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>());
+ int32_t layer = mFdp.ConsumeIntegral<int32_t>();
+ transaction.setLayer(surface, layer);
+
+ sp<SurfaceControl> relativeSurface = makeSurfaceControl();
+ transaction.setRelativeLayer(surface, relativeSurface, layer);
+
+ Region transparentRegion(getRect(&mFdp));
+ transaction.setTransparentRegionHint(surface, transparentRegion);
+ transaction.setAlpha(surface, mFdp.ConsumeFloatingPoint<float>());
+
+ transaction.setCornerRadius(surface, mFdp.ConsumeFloatingPoint<float>());
+ transaction.setBackgroundBlurRadius(surface, mFdp.ConsumeFloatingPoint<float>());
+ std::vector<BlurRegion> regions;
+ uint32_t vectorSize = mFdp.ConsumeIntegralInRange<uint32_t>(0, 100);
+ regions.resize(vectorSize);
+ for (size_t idx = 0; idx < vectorSize; ++idx) {
+ regions.push_back(getBlurRegion());
+ }
+ transaction.setBlurRegions(surface, regions);
+
+ transaction.setLayerStack(surface, {mFdp.ConsumeIntegral<uint32_t>()});
+ half3 color = {mFdp.ConsumeIntegral<uint32_t>(), mFdp.ConsumeIntegral<uint32_t>(),
+ mFdp.ConsumeIntegral<uint32_t>()};
+ transaction.setColor(surface, color);
+ transaction.setBackgroundColor(surface, color, mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.PickValueInArray(kDataspaces));
+
+ transaction.setApi(surface, mFdp.ConsumeIntegral<int32_t>());
+ transaction.setFrameRateSelectionPriority(surface, mFdp.ConsumeIntegral<int32_t>());
+ transaction.setColorSpaceAgnostic(surface, mFdp.ConsumeBool() /*agnostic*/);
+
+ gui::WindowInfo windowInfo;
+ getWindowInfo(&windowInfo);
+ transaction.setInputWindowInfo(surface, windowInfo);
+ Parcel windowParcel;
+ windowInfo.writeToParcel(&windowParcel);
+ windowParcel.setDataPosition(0);
+ windowInfo.readFromParcel(&windowParcel);
+
+ windowInfo.addTouchableRegion(getRect(&mFdp));
+ int32_t pointX = mFdp.ConsumeIntegral<int32_t>();
+ int32_t pointY = mFdp.ConsumeIntegral<int32_t>();
+ windowInfo.touchableRegionContainsPoint(pointX, pointY);
+ windowInfo.frameContainsPoint(pointX, pointY);
+
+ Parcel transactionParcel;
+ transaction.writeToParcel(&transactionParcel);
+ transactionParcel.setDataPosition(0);
+ transaction.readFromParcel(&transactionParcel);
+ SurfaceComposerClient::Transaction::createFromParcel(&transactionParcel);
+}
+
+void SurfaceComposerClientFuzzer::fuzzOnPullAtom() {
+ std::string outData;
+ bool success;
+ SurfaceComposerClient::onPullAtom(mFdp.ConsumeIntegral<int32_t>(), &outData, &success);
+}
+
+void SurfaceComposerClientFuzzer::invokeSurfaceComposerClient() {
+ String8 displayName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str());
+ sp<IBinder> displayToken =
+ SurfaceComposerClient::createDisplay(displayName, mFdp.ConsumeBool() /*secure*/);
+ SurfaceComposerClient::setDesiredDisplayModeSpecs(displayToken, mFdp.ConsumeIntegral<int32_t>(),
+ mFdp.ConsumeBool() /*allowGroupSwitching*/,
+ mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>(),
+ mFdp.ConsumeFloatingPoint<float>());
+
+ ui::ColorMode colorMode = mFdp.PickValueInArray(kColormodes);
+ SurfaceComposerClient::setActiveColorMode(displayToken, colorMode);
+ SurfaceComposerClient::setAutoLowLatencyMode(displayToken, mFdp.ConsumeBool() /*on*/);
+ SurfaceComposerClient::setGameContentType(displayToken, mFdp.ConsumeBool() /*on*/);
+ SurfaceComposerClient::setDisplayPowerMode(displayToken, mFdp.ConsumeIntegral<int32_t>());
+ SurfaceComposerClient::doUncacheBufferTransaction(mFdp.ConsumeIntegral<uint64_t>());
+
+ SurfaceComposerClient::setDisplayBrightness(displayToken, getBrightness(&mFdp));
+ hardware::power::Boost boostId = mFdp.PickValueInArray(kBoost);
+ SurfaceComposerClient::notifyPowerBoost((int32_t)boostId);
+
+ String8 surfaceName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str());
+ sp<BBinder> handle(new BBinder());
+ sp<BnGraphicBufferProducer> producer;
+ sp<Surface> surfaceParent(
+ new Surface(producer, mFdp.ConsumeBool() /*controlledByApp*/, handle));
+
+ SurfaceComposerClient::enableVSyncInjections(mFdp.ConsumeBool() /*secure*/);
+ nsecs_t when = mFdp.ConsumeIntegral<uint32_t>();
+ SurfaceComposerClient::injectVSync(when);
+
+ fuzzOnPullAtom();
+ SurfaceComposerClient::setDisplayContentSamplingEnabled(displayToken,
+ mFdp.ConsumeBool() /*enable*/,
+ mFdp.ConsumeIntegral<uint8_t>(),
+ mFdp.ConsumeIntegral<uint64_t>());
+
+ sp<IBinder> stopLayerHandle;
+ sp<gui::IRegionSamplingListener> listener = sp<gui::IRegionSamplingListenerDefault>::make();
+ sp<gui::IRegionSamplingListenerDelegator> sampleListener =
+ new gui::IRegionSamplingListenerDelegator(listener);
+ SurfaceComposerClient::addRegionSamplingListener(getRect(&mFdp), stopLayerHandle,
+ sampleListener);
+ sp<gui::IFpsListenerDefault> fpsListener;
+ SurfaceComposerClient::addFpsListener(mFdp.ConsumeIntegral<int32_t>(), fpsListener);
+}
+
+void SurfaceComposerClientFuzzer::invokeSurfaceComposerClientBinder() {
+ sp<FakeBnSurfaceComposerClient> client(new FakeBnSurfaceComposerClient());
+ fuzzService(client.get(), std::move(mFdp));
+}
+
+void SurfaceComposerClientFuzzer::process() {
+ invokeSurfaceComposerClient();
+ invokeSurfaceComposerTransaction();
+ invokeSurfaceComposerClientBinder();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ SurfaceComposerClientFuzzer surfaceComposerClientFuzzer(data, size);
+ surfaceComposerClientFuzzer.process();
+ return 0;
+}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 2ed5260..95df811 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -233,7 +233,7 @@
// Queues up transactions using this token in SurfaceFlinger. This prevents queued up
// transactions from other parts of the client from blocking this transaction.
- const sp<IBinder> mApplyToken GUARDED_BY(mMutex) = new BBinder();
+ const sp<IBinder> mApplyToken GUARDED_BY(mMutex) = sp<BBinder>::make();
// Guards access to mDequeueTimestamps since we cannot hold to mMutex in onFrameDequeued or
// we will deadlock.
diff --git a/libs/gui/include/gui/JankInfo.h b/libs/gui/include/gui/JankInfo.h
index ce9716f..1dddeba 100644
--- a/libs/gui/include/gui/JankInfo.h
+++ b/libs/gui/include/gui/JankInfo.h
@@ -24,9 +24,9 @@
None = 0x0,
// Jank that occurs in the layers below SurfaceFlinger
DisplayHAL = 0x1,
- // SF took too long on the CPU
+ // SF took too long on the CPU; deadline missed during HWC
SurfaceFlingerCpuDeadlineMissed = 0x2,
- // SF took too long on the GPU
+ // SF took too long on the GPU; deadline missed during GPU composition
SurfaceFlingerGpuDeadlineMissed = 0x4,
// Either App or GPU took too long on the frame
AppDeadlineMissed = 0x8,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index f3701e8..759fcc6 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -250,7 +250,7 @@
mat4 colorTransform;
std::vector<BlurRegion> blurRegions;
- sp<gui::WindowInfoHandle> windowInfoHandle = new gui::WindowInfoHandle();
+ sp<gui::WindowInfoHandle> windowInfoHandle = sp<gui::WindowInfoHandle>::make();
LayerMetadata metadata;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index d5f4414..20c38d8 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -341,6 +341,8 @@
// B B'
sp<SurfaceControl> mirrorSurface(SurfaceControl* mirrorFromSurface);
+ sp<SurfaceControl> mirrorDisplay(DisplayId displayId);
+
//! Create a virtual display
static sp<IBinder> createDisplay(const String8& displayName, bool secure);
@@ -349,7 +351,6 @@
//! Get stable IDs for connected physical displays
static std::vector<PhysicalDisplayId> getPhysicalDisplayIds();
- static status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*);
static std::optional<PhysicalDisplayId> getInternalDisplayId();
//! Get token for a physical display given its stable ID
diff --git a/libs/gui/include/gui/TraceUtils.h b/libs/gui/include/gui/TraceUtils.h
index 0009615..4c01683 100644
--- a/libs/gui/include/gui/TraceUtils.h
+++ b/libs/gui/include/gui/TraceUtils.h
@@ -21,13 +21,14 @@
#include <cutils/trace.h>
#include <utils/Trace.h>
-#define ATRACE_FORMAT(fmt, ...) \
- TraceUtils::TraceEnder __traceEnder = \
- (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), TraceUtils::TraceEnder())
+#define ATRACE_FORMAT(fmt, ...) \
+ TraceUtils::TraceEnder traceEnder = \
+ (CC_UNLIKELY(ATRACE_ENABLED()) && \
+ (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), true), \
+ TraceUtils::TraceEnder())
-#define ATRACE_FORMAT_BEGIN(fmt, ...) TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__)
-
-#define ATRACE_FORMAT_INSTANT(fmt, ...) TraceUtils::intantFormat(fmt, ##__VA_ARGS__)
+#define ATRACE_FORMAT_INSTANT(fmt, ...) \
+ (CC_UNLIKELY(ATRACE_ENABLED()) && (TraceUtils::instantFormat(fmt, ##__VA_ARGS__), true))
namespace android {
@@ -39,8 +40,6 @@
};
static void atraceFormatBegin(const char* fmt, ...) {
- if (CC_LIKELY(!ATRACE_ENABLED())) return;
-
const int BUFFER_SIZE = 256;
va_list ap;
char buf[BUFFER_SIZE];
@@ -52,9 +51,7 @@
ATRACE_BEGIN(buf);
}
- static void intantFormat(const char* fmt, ...) {
- if (CC_LIKELY(!ATRACE_ENABLED())) return;
-
+ static void instantFormat(const char* fmt, ...) {
const int BUFFER_SIZE = 256;
va_list ap;
char buf[BUFFER_SIZE];
@@ -65,7 +62,6 @@
ATRACE_INSTANT(buf);
}
+};
-}; // class TraceUtils
-
-} /* namespace android */
+} // namespace android
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index c6cdeb7..2637f59 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -1184,18 +1184,23 @@
std::vector<sp<IGraphicBufferProducer>> mProducers;
};
-TEST_F(MultiDisplayTests, drop_input_if_layer_on_invalid_display) {
+TEST_F(MultiDisplayTests, drop_touch_if_layer_on_invalid_display) {
ui::LayerStack layerStack = ui::LayerStack::fromValue(42);
// Do not create a display associated with the LayerStack.
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->doTransaction([&](auto &t, auto &sc) { t.setLayerStack(sc, layerStack); });
surface->showAt(100, 100);
+ // Touches should be dropped if the layer is on an invalid display.
injectTapOnDisplay(101, 101, layerStack.id);
- surface->requestFocus(layerStack.id);
- injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
-
EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+ // However, we still let the window be focused and receive keys.
+ surface->requestFocus(layerStack.id);
+ surface->assertFocusChange(true);
+
+ injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
+ surface->expectKey(AKEYCODE_V);
}
TEST_F(MultiDisplayTests, virtual_display_receives_input) {
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 391a0aa..71f2ad4 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -745,10 +745,6 @@
return binder::Status::ok();
}
- binder::Status getPrimaryPhysicalDisplayId(int64_t* /*outDisplayId*/) override {
- return binder::Status::ok();
- }
-
binder::Status getPhysicalDisplayToken(int64_t /*displayId*/,
sp<IBinder>* /*outDisplay*/) override {
return binder::Status::ok();
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 375b684..155cb04 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -90,6 +90,25 @@
}
}
+const char* motionToolTypeToString(int32_t toolType) {
+ switch (toolType) {
+ case AMOTION_EVENT_TOOL_TYPE_UNKNOWN:
+ return "UNKNOWN";
+ case AMOTION_EVENT_TOOL_TYPE_FINGER:
+ return "FINGER";
+ case AMOTION_EVENT_TOOL_TYPE_STYLUS:
+ return "STYLUS";
+ case AMOTION_EVENT_TOOL_TYPE_MOUSE:
+ return "MOUSE";
+ case AMOTION_EVENT_TOOL_TYPE_ERASER:
+ return "ERASER";
+ case AMOTION_EVENT_TOOL_TYPE_PALM:
+ return "PALM";
+ default:
+ return "INVALID";
+ }
+}
+
// --- IdGenerator ---
IdGenerator::IdGenerator(Source source) : mSource(source) {}
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 2039fa6..422e6e0 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -304,9 +304,8 @@
char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const {
char16_t result = 0;
- const Key* key;
- const Behavior* behavior;
- if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+ const Behavior* behavior = getKeyBehavior(keyCode, metaState);
+ if (behavior != nullptr) {
result = behavior->character;
}
#if DEBUG_MAPPING
@@ -321,9 +320,8 @@
outFallbackAction->metaState = 0;
bool result = false;
- const Key* key;
- const Behavior* behavior;
- if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+ const Behavior* behavior = getKeyBehavior(keyCode, metaState);
+ if (behavior != nullptr) {
if (behavior->fallbackKeyCode) {
outFallbackAction->keyCode = behavior->fallbackKeyCode;
outFallbackAction->metaState = metaState & ~behavior->metaState;
@@ -347,12 +345,12 @@
// Try to find the most general behavior that maps to this character.
// For example, the base key behavior will usually be last in the list.
// However, if we find a perfect meta state match for one behavior then use that one.
- for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
- if (behavior->character) {
+ for (const Behavior& behavior : key->behaviors) {
+ if (behavior.character) {
for (size_t i = 0; i < numChars; i++) {
- if (behavior->character == chars[i]) {
- result = behavior->character;
- if ((behavior->metaState & metaState) == behavior->metaState) {
+ if (behavior.character == chars[i]) {
+ result = behavior.character;
+ if ((behavior.metaState & metaState) == behavior.metaState) {
goto ExactMatch;
}
break;
@@ -438,9 +436,8 @@
*outKeyCode = keyCode;
*outMetaState = metaState;
- const Key* key;
- const Behavior* behavior;
- if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+ const Behavior* behavior = getKeyBehavior(keyCode, metaState);
+ if (behavior != nullptr) {
if (behavior->replacementKeyCode) {
*outKeyCode = behavior->replacementKeyCode;
int32_t newMetaState = metaState & ~behavior->metaState;
@@ -484,21 +481,17 @@
return false;
}
-bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState,
- const Key** outKey, const Behavior** outBehavior) const {
+const KeyCharacterMap::Behavior* KeyCharacterMap::getKeyBehavior(int32_t keyCode,
+ int32_t metaState) const {
const Key* key;
if (getKey(keyCode, &key)) {
- const Behavior* behavior = key->firstBehavior;
- while (behavior) {
- if (matchesMetaState(metaState, behavior->metaState)) {
- *outKey = key;
- *outBehavior = behavior;
- return true;
+ for (const Behavior& behavior : key->behaviors) {
+ if (matchesMetaState(metaState, behavior.metaState)) {
+ return &behavior;
}
- behavior = behavior->next;
}
}
- return false;
+ return nullptr;
}
bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) {
@@ -543,12 +536,12 @@
// Try to find the most general behavior that maps to this character.
// For example, the base key behavior will usually be last in the list.
const Behavior* found = nullptr;
- for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
- if (behavior->character == ch) {
- found = behavior;
+ for (const Behavior& behavior : key->behaviors) {
+ if (behavior.character == ch) {
+ found = &behavior;
}
}
- if (found) {
+ if (found != nullptr) {
*outKeyCode = mKeys.keyAt(i);
*outMetaState = found->metaState;
return true;
@@ -706,7 +699,6 @@
key->number = number;
map->mKeys.add(keyCode, key);
- Behavior* lastBehavior = nullptr;
while (parcel->readInt32()) {
int32_t metaState = parcel->readInt32();
char16_t character = parcel->readInt32();
@@ -716,17 +708,12 @@
return nullptr;
}
- Behavior* behavior = new Behavior();
- behavior->metaState = metaState;
- behavior->character = character;
- behavior->fallbackKeyCode = fallbackKeyCode;
- behavior->replacementKeyCode = replacementKeyCode;
- if (lastBehavior) {
- lastBehavior->next = behavior;
- } else {
- key->firstBehavior = behavior;
- }
- lastBehavior = behavior;
+ key->behaviors.push_back({
+ .metaState = metaState,
+ .character = character,
+ .fallbackKeyCode = fallbackKeyCode,
+ .replacementKeyCode = replacementKeyCode,
+ });
}
if (parcel->errorCheck()) {
@@ -777,13 +764,12 @@
parcel->writeInt32(keyCode);
parcel->writeInt32(key->label);
parcel->writeInt32(key->number);
- for (const Behavior* behavior = key->firstBehavior; behavior != nullptr;
- behavior = behavior->next) {
+ for (const Behavior& behavior : key->behaviors) {
parcel->writeInt32(1);
- parcel->writeInt32(behavior->metaState);
- parcel->writeInt32(behavior->character);
- parcel->writeInt32(behavior->fallbackKeyCode);
- parcel->writeInt32(behavior->replacementKeyCode);
+ parcel->writeInt32(behavior.metaState);
+ parcel->writeInt32(behavior.character);
+ parcel->writeInt32(behavior.fallbackKeyCode);
+ parcel->writeInt32(behavior.replacementKeyCode);
}
parcel->writeInt32(0);
}
@@ -804,38 +790,10 @@
// --- KeyCharacterMap::Key ---
-KeyCharacterMap::Key::Key() :
- label(0), number(0), firstBehavior(nullptr) {
-}
+KeyCharacterMap::Key::Key() : label(0), number(0) {}
-KeyCharacterMap::Key::Key(const Key& other) :
- label(other.label), number(other.number),
- firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : nullptr) {
-}
-
-KeyCharacterMap::Key::~Key() {
- Behavior* behavior = firstBehavior;
- while (behavior) {
- Behavior* next = behavior->next;
- delete behavior;
- behavior = next;
- }
-}
-
-
-// --- KeyCharacterMap::Behavior ---
-
-KeyCharacterMap::Behavior::Behavior() :
- next(nullptr), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
-}
-
-KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
- next(other.next ? new Behavior(*other.next) : nullptr),
- metaState(other.metaState), character(other.character),
- fallbackKeyCode(other.fallbackKeyCode),
- replacementKeyCode(other.replacementKeyCode) {
-}
-
+KeyCharacterMap::Key::Key(const Key& other)
+ : label(other.label), number(other.number), behaviors(other.behaviors) {}
// --- KeyCharacterMap::Parser ---
@@ -1213,23 +1171,21 @@
#endif
break;
case PROPERTY_META: {
- for (Behavior* b = key->firstBehavior; b; b = b->next) {
- if (b->metaState == property.metaState) {
+ for (const Behavior& b : key->behaviors) {
+ if (b.metaState == property.metaState) {
ALOGE("%s: Duplicate key behavior for modifier.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
}
- Behavior* newBehavior = new Behavior(behavior);
- newBehavior->metaState = property.metaState;
- newBehavior->next = key->firstBehavior;
- key->firstBehavior = newBehavior;
-#if DEBUG_PARSER
- ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
- mKeyCode,
- newBehavior->metaState, newBehavior->character,
- newBehavior->fallbackKeyCode, newBehavior->replacementKeyCode);
-#endif
+ Behavior newBehavior = behavior;
+ newBehavior.metaState = property.metaState;
+ key->behaviors.push_front(newBehavior);
+ ALOGD_IF(DEBUG_PARSER,
+ "Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
+ mKeyCode, key->behaviors.front().metaState, key->behaviors.front().character,
+ key->behaviors.front().fallbackKeyCode,
+ key->behaviors.front().replacementKeyCode);
break;
}
}
@@ -1242,8 +1198,8 @@
if (!key->number) {
char16_t digit = 0;
char16_t symbol = 0;
- for (Behavior* b = key->firstBehavior; b; b = b->next) {
- char16_t ch = b->character;
+ for (const Behavior& b : key->behaviors) {
+ char16_t ch = b.character;
if (ch) {
if (ch >= '0' && ch <= '9') {
digit = ch;
diff --git a/libs/math/OWNERS b/libs/math/OWNERS
index 72d33bc..82ae422 100644
--- a/libs/math/OWNERS
+++ b/libs/math/OWNERS
@@ -1,3 +1,5 @@
mathias@google.com
randolphs@google.com
romainguy@google.com
+sumir@google.com
+jreck@google.com
diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp
index ead97cf..7bcfff5 100644
--- a/libs/renderengine/benchmark/RenderEngineBench.cpp
+++ b/libs/renderengine/benchmark/RenderEngineBench.cpp
@@ -117,11 +117,12 @@
uint64_t extraUsageFlags = 0,
std::string name = "output") {
return std::make_shared<
- impl::ExternalTexture>(new GraphicBuffer(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GRALLOC_USAGE_HW_RENDER |
- GRALLOC_USAGE_HW_TEXTURE |
- extraUsageFlags,
- std::move(name)),
+ impl::ExternalTexture>(sp<GraphicBuffer>::make(width, height,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1u,
+ GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_TEXTURE |
+ extraUsageFlags,
+ std::move(name)),
re,
impl::ExternalTexture::Usage::READABLE |
impl::ExternalTexture::Usage::WRITEABLE);
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 6dc01b9..9a5ff54 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -454,8 +454,9 @@
mImageManager->initThread();
mDrawingBuffer = createFramebuffer();
sp<GraphicBuffer> buf =
- new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888, 1,
- GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, "placeholder");
+ sp<GraphicBuffer>::make(1, 1, PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE,
+ "placeholder");
const status_t err = buf->initCheck();
if (err != OK) {
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index c39f0a9..f6b9183 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -364,8 +364,8 @@
const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
sp<GraphicBuffer> dstBuffer =
- new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
- 1, usage, "primeShaderCache_dst");
+ sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
+ PIXEL_FORMAT_RGBA_8888, 1, usage, "primeShaderCache_dst");
const auto dstTexture =
std::make_shared<impl::ExternalTexture>(dstBuffer, *renderengine,
@@ -375,8 +375,8 @@
// something, but the details are not important. Make use of the shadow layer drawing step
// to populate it.
sp<GraphicBuffer> srcBuffer =
- new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
- 1, usage, "drawImageLayer_src");
+ sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
+ PIXEL_FORMAT_RGBA_8888, 1, usage, "drawImageLayer_src");
const auto srcTexture = std::make_shared<
impl::ExternalTexture>(srcBuffer, *renderengine,
@@ -398,8 +398,9 @@
// GRALLOC_USAGE_HW_TEXTURE should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE.
const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE;
sp<GraphicBuffer> externalBuffer =
- new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
- 1, usageExternal, "primeShaderCache_external");
+ sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
+ PIXEL_FORMAT_RGBA_8888, 1, usageExternal,
+ "primeShaderCache_external");
const auto externalTexture =
std::make_shared<impl::ExternalTexture>(externalBuffer, *renderengine,
impl::ExternalTexture::Usage::READABLE);
@@ -409,8 +410,9 @@
// Another external texture with a different pixel format triggers useIsOpaqueWorkaround.
// It doesn't have to be f16, but it can't be the usual 8888.
sp<GraphicBuffer> f16ExternalBuffer =
- new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_FP16,
- 1, usageExternal, "primeShaderCache_external_f16");
+ sp<GraphicBuffer>::make(displayRect.width(), displayRect.height(),
+ PIXEL_FORMAT_RGBA_FP16, 1, usageExternal,
+ "primeShaderCache_external_f16");
// The F16 texture may not be usable on all devices, so check first that it was created.
status_t error = f16ExternalBuffer->initCheck();
if (!error) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index a0bba59..347b8b7 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -24,43 +24,11 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GrContextOptions.h>
-#include <SkBlendMode.h>
-#include <SkCanvas.h>
-#include <SkColor.h>
-#include <SkColorFilter.h>
-#include <SkColorMatrix.h>
-#include <SkColorSpace.h>
-#include <SkData.h>
-#include <SkGraphics.h>
-#include <SkImage.h>
-#include <SkImageFilters.h>
-#include <SkImageInfo.h>
-#include <SkM44.h>
-#include <SkMatrix.h>
-#include <SkPaint.h>
-#include <SkPath.h>
-#include <SkPoint.h>
-#include <SkPoint3.h>
-#include <SkRect.h>
-#include <SkRefCnt.h>
-#include <SkRegion.h>
-#include <SkRRect.h>
-#include <SkRuntimeEffect.h>
-#include <SkSamplingOptions.h>
-#include <SkScalar.h>
-#include <SkShader.h>
-#include <SkShadowUtils.h>
-#include <SkString.h>
-#include <SkSurface.h>
-#include <SkTileMode.h>
#include <android-base/stringprintf.h>
#include <gl/GrGLInterface.h>
#include <gui/TraceUtils.h>
#include <sync/sync.h>
-#include <ui/BlurRegion.h>
-#include <ui/DataspaceUtils.h>
#include <ui/DebugUtils.h>
-#include <ui/GraphicBuffer.h>
#include <utils/Trace.h>
#include <cmath>
@@ -69,23 +37,7 @@
#include <numeric>
#include "../gl/GLExtensions.h"
-#include "Cache.h"
-#include "ColorSpaces.h"
-#include "filters/BlurFilter.h"
-#include "filters/GaussianBlurFilter.h"
-#include "filters/KawaseBlurFilter.h"
-#include "filters/LinearEffect.h"
#include "log/log_main.h"
-#include "skia/debug/SkiaCapture.h"
-#include "skia/debug/SkiaMemoryReporter.h"
-#include "skia/filters/StretchShaderFactory.h"
-#include "system/graphics-base-v1.0.h"
-
-namespace {
-// Debugging settings
-static const bool kPrintLayerSettings = false;
-static const bool kFlushAfterEveryLayer = kPrintLayerSettings;
-} // namespace
bool checkGlError(const char* op, int lineNumber);
@@ -244,6 +196,7 @@
std::unique_ptr<SkiaGLRenderEngine> engine =
std::make_unique<SkiaGLRenderEngine>(args, display, ctxt, placeholder, protectedContext,
protectedPlaceholder);
+ engine->ensureGrContextsCreated();
ALOGI("OpenGL ES informations:");
ALOGI("vendor : %s", extensions.getVendor());
@@ -256,11 +209,6 @@
return engine;
}
-std::future<void> SkiaGLRenderEngine::primeCache() {
- Cache::primeShaderCache(this);
- return {};
-}
-
EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
status_t err;
EGLConfig config;
@@ -300,72 +248,20 @@
return config;
}
-sk_sp<SkData> SkiaGLRenderEngine::SkSLCacheMonitor::load(const SkData& key) {
- // This "cache" does not actually cache anything. It just allows us to
- // monitor Skia's internal cache. So this method always returns null.
- return nullptr;
-}
-
-void SkiaGLRenderEngine::SkSLCacheMonitor::store(const SkData& key, const SkData& data,
- const SkString& description) {
- mShadersCachedSinceLastCall++;
- mTotalShadersCompiled++;
- ATRACE_FORMAT("SF cache: %i shaders", mTotalShadersCompiled);
-}
-
-int SkiaGLRenderEngine::reportShadersCompiled() {
- return mSkSLCacheMonitor.totalShadersCompiled();
-}
-
SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
EGLContext ctxt, EGLSurface placeholder,
EGLContext protectedContext, EGLSurface protectedPlaceholder)
- : SkiaRenderEngine(args.renderEngineType),
+ : SkiaRenderEngine(args.renderEngineType,
+ static_cast<PixelFormat>(args.pixelFormat),
+ args.useColorManagement, args.supportsBackgroundBlur),
mEGLDisplay(display),
mEGLContext(ctxt),
mPlaceholderSurface(placeholder),
mProtectedEGLContext(protectedContext),
- mProtectedPlaceholderSurface(protectedPlaceholder),
- mDefaultPixelFormat(static_cast<PixelFormat>(args.pixelFormat)),
- mUseColorManagement(args.useColorManagement) {
- sk_sp<const GrGLInterface> glInterface = GrGLMakeNativeInterface();
- LOG_ALWAYS_FATAL_IF(!glInterface.get());
-
- GrContextOptions options;
- options.fDisableDriverCorrectnessWorkarounds = true;
- options.fDisableDistanceFieldPaths = true;
- options.fReducedShaderVariations = true;
- options.fPersistentCache = &mSkSLCacheMonitor;
- mGrContext = GrDirectContext::MakeGL(glInterface, options);
- if (supportsProtectedContent()) {
- useProtectedContext(true);
- mProtectedGrContext = GrDirectContext::MakeGL(glInterface, options);
- useProtectedContext(false);
- }
-
- if (args.supportsBackgroundBlur) {
- ALOGD("Background Blurs Enabled");
- mBlurFilter = new KawaseBlurFilter();
- }
- mCapture = std::make_unique<SkiaCapture>();
-}
+ mProtectedPlaceholderSurface(protectedPlaceholder) { }
SkiaGLRenderEngine::~SkiaGLRenderEngine() {
- std::lock_guard<std::mutex> lock(mRenderingMutex);
- if (mBlurFilter) {
- delete mBlurFilter;
- }
-
- mCapture = nullptr;
-
- mGrContext->flushAndSubmit(true);
- mGrContext->abandonContext();
-
- if (mProtectedGrContext) {
- mProtectedGrContext->flushAndSubmit(true);
- mProtectedGrContext->abandonContext();
- }
-
+ finishRenderingAndAbandonContext();
if (mPlaceholderSurface != EGL_NO_SURFACE) {
eglDestroySurface(mEGLDisplay, mPlaceholderSurface);
}
@@ -383,71 +279,69 @@
eglReleaseThread();
}
-bool SkiaGLRenderEngine::supportsProtectedContent() const {
+SkiaRenderEngine::Contexts SkiaGLRenderEngine::createDirectContexts(
+ const GrContextOptions& options) {
+
+ LOG_ALWAYS_FATAL_IF(isProtected(),
+ "Cannot setup contexts while already in protected mode");
+
+ sk_sp<const GrGLInterface> glInterface = GrGLMakeNativeInterface();
+
+ LOG_ALWAYS_FATAL_IF(!glInterface.get(), "GrGLMakeNativeInterface() failed");
+
+ SkiaRenderEngine::Contexts contexts;
+ contexts.first = GrDirectContext::MakeGL(glInterface, options);
+ if (supportsProtectedContentImpl()) {
+ useProtectedContextImpl(GrProtected::kYes);
+ contexts.second = GrDirectContext::MakeGL(glInterface, options);
+ useProtectedContextImpl(GrProtected::kNo);
+ }
+
+ return contexts;
+}
+
+bool SkiaGLRenderEngine::supportsProtectedContentImpl() const {
return mProtectedEGLContext != EGL_NO_CONTEXT;
}
-GrDirectContext* SkiaGLRenderEngine::getActiveGrContext() const {
- return mInProtectedContext ? mProtectedGrContext.get() : mGrContext.get();
-}
-
-void SkiaGLRenderEngine::useProtectedContext(bool useProtectedContext) {
- if (useProtectedContext == mInProtectedContext ||
- (useProtectedContext && !supportsProtectedContent())) {
- return;
- }
-
- // release any scratch resources before switching into a new mode
- if (getActiveGrContext()) {
- getActiveGrContext()->purgeUnlockedResources(true);
- }
-
+bool SkiaGLRenderEngine::useProtectedContextImpl(GrProtected isProtected) {
const EGLSurface surface =
- useProtectedContext ? mProtectedPlaceholderSurface : mPlaceholderSurface;
- const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
+ (isProtected == GrProtected::kYes) ?
+ mProtectedPlaceholderSurface : mPlaceholderSurface;
+ const EGLContext context = (isProtected == GrProtected::kYes) ?
+ mProtectedEGLContext : mEGLContext;
- if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) {
- mInProtectedContext = useProtectedContext;
- // given that we are sharing the same thread between two GrContexts we need to
- // make sure that the thread state is reset when switching between the two.
- if (getActiveGrContext()) {
- getActiveGrContext()->resetContext();
- }
- }
+ return eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
}
-base::unique_fd SkiaGLRenderEngine::flush() {
- ATRACE_CALL();
- if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) {
- return base::unique_fd();
- }
-
- EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
- if (sync == EGL_NO_SYNC_KHR) {
- ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
- return base::unique_fd();
- }
-
- // native fence fd will not be populated until flush() is done.
- glFlush();
-
- // get the fence fd
- base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
- eglDestroySyncKHR(mEGLDisplay, sync);
- if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
- ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
- }
-
- return fenceFd;
-}
-
-void SkiaGLRenderEngine::waitFence(base::borrowed_fd fenceFd) {
+void SkiaGLRenderEngine::waitFence(GrDirectContext*, base::borrowed_fd fenceFd) {
if (fenceFd.get() >= 0 && !waitGpuFence(fenceFd)) {
ATRACE_NAME("SkiaGLRenderEngine::waitFence");
sync_wait(fenceFd.get(), -1);
}
}
+base::unique_fd SkiaGLRenderEngine::flushAndSubmit(GrDirectContext* grContext) {
+ base::unique_fd drawFence = flush();
+
+ bool requireSync = drawFence.get() < 0;
+ if (requireSync) {
+ ATRACE_BEGIN("Submit(sync=true)");
+ } else {
+ ATRACE_BEGIN("Submit(sync=false)");
+ }
+ bool success = grContext->submit(requireSync);
+ ATRACE_END();
+ if (!success) {
+ ALOGE("Failed to flush RenderEngine commands");
+ // Chances are, something illegal happened (Skia's internal GPU object
+ // doesn't exist, or the context was abandoned).
+ return drawFence;
+ }
+
+ return drawFence;
+}
+
bool SkiaGLRenderEngine::waitGpuFence(base::borrowed_fd fenceFd) {
if (!gl::GLExtensions::getInstance().hasNativeFenceSync() ||
!gl::GLExtensions::getInstance().hasWaitSync()) {
@@ -483,974 +377,29 @@
return true;
}
-static float toDegrees(uint32_t transform) {
- switch (transform) {
- case ui::Transform::ROT_90:
- return 90.0;
- case ui::Transform::ROT_180:
- return 180.0;
- case ui::Transform::ROT_270:
- return 270.0;
- default:
- return 0.0;
- }
-}
-
-static SkColorMatrix toSkColorMatrix(const mat4& matrix) {
- return SkColorMatrix(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0], 0, matrix[0][1],
- matrix[1][1], matrix[2][1], matrix[3][1], 0, matrix[0][2], matrix[1][2],
- matrix[2][2], matrix[3][2], 0, matrix[0][3], matrix[1][3], matrix[2][3],
- matrix[3][3], 0);
-}
-
-static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destinationDataspace) {
- int64_t sourceTransfer = sourceDataspace & HAL_DATASPACE_TRANSFER_MASK;
- int64_t destTransfer = destinationDataspace & HAL_DATASPACE_TRANSFER_MASK;
-
- // Treat unsupported dataspaces as srgb
- if (destTransfer != HAL_DATASPACE_TRANSFER_LINEAR &&
- destTransfer != HAL_DATASPACE_TRANSFER_HLG &&
- destTransfer != HAL_DATASPACE_TRANSFER_ST2084) {
- destTransfer = HAL_DATASPACE_TRANSFER_SRGB;
- }
-
- if (sourceTransfer != HAL_DATASPACE_TRANSFER_LINEAR &&
- sourceTransfer != HAL_DATASPACE_TRANSFER_HLG &&
- sourceTransfer != HAL_DATASPACE_TRANSFER_ST2084) {
- sourceTransfer = HAL_DATASPACE_TRANSFER_SRGB;
- }
-
- const bool isSourceLinear = sourceTransfer == HAL_DATASPACE_TRANSFER_LINEAR;
- const bool isSourceSRGB = sourceTransfer == HAL_DATASPACE_TRANSFER_SRGB;
- const bool isDestLinear = destTransfer == HAL_DATASPACE_TRANSFER_LINEAR;
- const bool isDestSRGB = destTransfer == HAL_DATASPACE_TRANSFER_SRGB;
-
- return !(isSourceLinear && isDestSRGB) && !(isSourceSRGB && isDestLinear) &&
- sourceTransfer != destTransfer;
-}
-
-void SkiaGLRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
- bool isRenderable) {
- // Only run this if RE is running on its own thread. This way the access to GL
- // operations is guaranteed to be happening on the same thread.
- if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED) {
- return;
- }
- // We currently don't attempt to map a buffer if the buffer contains protected content
- // because GPU resources for protected buffers is much more limited.
- const bool isProtectedBuffer = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
- if (isProtectedBuffer) {
- return;
- }
+base::unique_fd SkiaGLRenderEngine::flush() {
ATRACE_CALL();
-
- // If we were to support caching protected buffers then we will need to switch the
- // currently bound context if we are not already using the protected context (and subsequently
- // switch back after the buffer is cached). However, for non-protected content we can bind
- // the texture in either GL context because they are initialized with the same share_context
- // which allows the texture state to be shared between them.
- auto grContext = getActiveGrContext();
- auto& cache = mTextureCache;
-
- std::lock_guard<std::mutex> lock(mRenderingMutex);
- mGraphicBufferExternalRefs[buffer->getId()]++;
-
- if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) {
- std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef =
- std::make_shared<AutoBackendTexture::LocalRef>(grContext,
- buffer->toAHardwareBuffer(),
- isRenderable, mTextureCleanupMgr);
- cache.insert({buffer->getId(), imageTextureRef});
- }
-}
-
-void SkiaGLRenderEngine::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
- ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mRenderingMutex);
- if (const auto& iter = mGraphicBufferExternalRefs.find(buffer->getId());
- iter != mGraphicBufferExternalRefs.end()) {
- if (iter->second == 0) {
- ALOGW("Attempted to unmap GraphicBuffer <id: %" PRId64
- "> from RenderEngine texture, but the "
- "ref count was already zero!",
- buffer->getId());
- mGraphicBufferExternalRefs.erase(buffer->getId());
- return;
- }
-
- iter->second--;
-
- // Swap contexts if needed prior to deleting this buffer
- // See Issue 1 of
- // https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_protected_content.txt: even
- // when a protected context and an unprotected context are part of the same share group,
- // protected surfaces may not be accessed by an unprotected context, implying that protected
- // surfaces may only be freed when a protected context is active.
- const bool inProtected = mInProtectedContext;
- useProtectedContext(buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
-
- if (iter->second == 0) {
- mTextureCache.erase(buffer->getId());
- mGraphicBufferExternalRefs.erase(buffer->getId());
- }
-
- // Swap back to the previous context so that cached values of isProtected in SurfaceFlinger
- // are up-to-date.
- if (inProtected != mInProtectedContext) {
- useProtectedContext(inProtected);
- }
- }
-}
-
-bool SkiaGLRenderEngine::canSkipPostRenderCleanup() const {
- std::lock_guard<std::mutex> lock(mRenderingMutex);
- return mTextureCleanupMgr.isEmpty();
-}
-
-void SkiaGLRenderEngine::cleanupPostRender() {
- ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mRenderingMutex);
- mTextureCleanupMgr.cleanup();
-}
-
-// Helper class intended to be used on the stack to ensure that texture cleanup
-// is deferred until after this class goes out of scope.
-class DeferTextureCleanup final {
-public:
- DeferTextureCleanup(AutoBackendTexture::CleanupManager& mgr) : mMgr(mgr) {
- mMgr.setDeferredStatus(true);
- }
- ~DeferTextureCleanup() { mMgr.setDeferredStatus(false); }
-
-private:
- DISALLOW_COPY_AND_ASSIGN(DeferTextureCleanup);
- AutoBackendTexture::CleanupManager& mMgr;
-};
-
-sk_sp<SkShader> SkiaGLRenderEngine::createRuntimeEffectShader(
- const RuntimeEffectShaderParameters& parameters) {
- // The given surface will be stretched by HWUI via matrix transformation
- // which gets similar results for most surfaces
- // Determine later on if we need to leverage the stertch shader within
- // surface flinger
- const auto& stretchEffect = parameters.layer.stretchEffect;
- auto shader = parameters.shader;
- if (stretchEffect.hasEffect()) {
- const auto targetBuffer = parameters.layer.source.buffer.buffer;
- const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
- if (graphicBuffer && parameters.shader) {
- shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
- }
+ if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) {
+ return base::unique_fd();
}
- if (parameters.requiresLinearEffect) {
- const ui::Dataspace inputDataspace = mUseColorManagement ? parameters.layer.sourceDataspace
- : ui::Dataspace::V0_SRGB_LINEAR;
- const ui::Dataspace outputDataspace = mUseColorManagement
- ? parameters.display.outputDataspace
- : ui::Dataspace::V0_SRGB_LINEAR;
-
- auto effect =
- shaders::LinearEffect{.inputDataspace = inputDataspace,
- .outputDataspace = outputDataspace,
- .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha};
-
- auto effectIter = mRuntimeEffects.find(effect);
- sk_sp<SkRuntimeEffect> runtimeEffect = nullptr;
- if (effectIter == mRuntimeEffects.end()) {
- runtimeEffect = buildRuntimeEffect(effect);
- mRuntimeEffects.insert({effect, runtimeEffect});
- } else {
- runtimeEffect = effectIter->second;
- }
- mat4 colorTransform = parameters.layer.colorTransform;
-
- colorTransform *=
- mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio,
- parameters.layerDimmingRatio, 1.f));
- const auto targetBuffer = parameters.layer.source.buffer.buffer;
- const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
- const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr;
- return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform,
- parameters.display.maxLuminance,
- parameters.display.currentLuminanceNits,
- parameters.layer.source.buffer.maxLuminanceNits,
- hardwareBuffer, parameters.display.renderIntent);
- }
- return parameters.shader;
-}
-
-void SkiaGLRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
- if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
- // Record display settings when capture is running.
- std::stringstream displaySettings;
- PrintTo(display, &displaySettings);
- // Store the DisplaySettings in additional information.
- canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
- SkData::MakeWithCString(displaySettings.str().c_str()));
+ EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
+ return base::unique_fd();
}
- // Before doing any drawing, let's make sure that we'll start at the origin of the display.
- // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
- // displays might have different scaling when compared to the physical screen.
+ // native fence fd will not be populated until flush() is done.
+ glFlush();
- canvas->clipRect(getSkRect(display.physicalDisplay));
- canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
-
- const auto clipWidth = display.clip.width();
- const auto clipHeight = display.clip.height();
- auto rotatedClipWidth = clipWidth;
- auto rotatedClipHeight = clipHeight;
- // Scale is contingent on the rotation result.
- if (display.orientation & ui::Transform::ROT_90) {
- std::swap(rotatedClipWidth, rotatedClipHeight);
- }
- const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
- static_cast<SkScalar>(rotatedClipWidth);
- const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
- static_cast<SkScalar>(rotatedClipHeight);
- canvas->scale(scaleX, scaleY);
-
- // Canvas rotation is done by centering the clip window at the origin, rotating, translating
- // back so that the top left corner of the clip is at (0, 0).
- canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
- canvas->rotate(toDegrees(display.orientation));
- canvas->translate(-clipWidth / 2, -clipHeight / 2);
- canvas->translate(-display.clip.left, -display.clip.top);
-}
-
-class AutoSaveRestore {
-public:
- AutoSaveRestore(SkCanvas* canvas) : mCanvas(canvas) { mSaveCount = canvas->save(); }
- ~AutoSaveRestore() { restore(); }
- void replace(SkCanvas* canvas) {
- mCanvas = canvas;
- mSaveCount = canvas->save();
- }
- void restore() {
- if (mCanvas) {
- mCanvas->restoreToCount(mSaveCount);
- mCanvas = nullptr;
- }
+ // get the fence fd
+ base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
+ eglDestroySyncKHR(mEGLDisplay, sync);
+ if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
}
-private:
- SkCanvas* mCanvas;
- int mSaveCount;
-};
-
-static SkRRect getBlurRRect(const BlurRegion& region) {
- const auto rect = SkRect::MakeLTRB(region.left, region.top, region.right, region.bottom);
- const SkVector radii[4] = {SkVector::Make(region.cornerRadiusTL, region.cornerRadiusTL),
- SkVector::Make(region.cornerRadiusTR, region.cornerRadiusTR),
- SkVector::Make(region.cornerRadiusBR, region.cornerRadiusBR),
- SkVector::Make(region.cornerRadiusBL, region.cornerRadiusBL)};
- SkRRect roundedRect;
- roundedRect.setRectRadii(rect, radii);
- return roundedRect;
-}
-
-// Arbitrary default margin which should be close enough to zero.
-constexpr float kDefaultMargin = 0.0001f;
-static bool equalsWithinMargin(float expected, float value, float margin = kDefaultMargin) {
- LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!");
- return std::abs(expected - value) < margin;
-}
-
-namespace {
-template <typename T>
-void logSettings(const T& t) {
- std::stringstream stream;
- PrintTo(t, &stream);
- auto string = stream.str();
- size_t pos = 0;
- // Perfetto ignores \n, so split up manually into separate ALOGD statements.
- const size_t size = string.size();
- while (pos < size) {
- const size_t end = std::min(string.find("\n", pos), size);
- ALOGD("%s", string.substr(pos, end - pos).c_str());
- pos = end + 1;
- }
-}
-} // namespace
-
-void SkiaGLRenderEngine::drawLayersInternal(
- const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
- const DisplaySettings& display, const std::vector<LayerSettings>& layers,
- const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/,
- base::unique_fd&& bufferFence) {
- ATRACE_NAME("SkiaGL::drawLayersInternal");
-
- std::lock_guard<std::mutex> lock(mRenderingMutex);
- if (buffer == nullptr) {
- ALOGE("No output buffer provided. Aborting GPU composition.");
- resultPromise->set_value({BAD_VALUE, base::unique_fd()});
- return;
- }
-
- validateOutputBufferUsage(buffer->getBuffer());
-
- auto grContext = getActiveGrContext();
- auto& cache = mTextureCache;
-
- // any AutoBackendTexture deletions will now be deferred until cleanupPostRender is called
- DeferTextureCleanup dtc(mTextureCleanupMgr);
-
- std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef;
- if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) {
- surfaceTextureRef = it->second;
- } else {
- surfaceTextureRef =
- std::make_shared<AutoBackendTexture::LocalRef>(grContext,
- buffer->getBuffer()
- ->toAHardwareBuffer(),
- true, mTextureCleanupMgr);
- }
-
- // wait on the buffer to be ready to use prior to using it
- waitFence(bufferFence);
-
- const ui::Dataspace dstDataspace =
- mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR;
- sk_sp<SkSurface> dstSurface = surfaceTextureRef->getOrCreateSurface(dstDataspace, grContext);
-
- SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
- if (dstCanvas == nullptr) {
- ALOGE("Cannot acquire canvas from Skia.");
- resultPromise->set_value({BAD_VALUE, base::unique_fd()});
- return;
- }
-
- // setup color filter if necessary
- sk_sp<SkColorFilter> displayColorTransform;
- if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
- displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform));
- }
- const bool ctModifiesAlpha =
- displayColorTransform && !displayColorTransform->isAlphaUnchanged();
-
- // Find the max layer white point to determine the max luminance of the scene...
- const float maxLayerWhitePoint = std::transform_reduce(
- layers.cbegin(), layers.cend(), 0.f,
- [](float left, float right) { return std::max(left, right); },
- [&](const auto& l) { return l.whitePointNits; });
-
- // ...and compute the dimming ratio if dimming is requested
- const float displayDimmingRatio = display.targetLuminanceNits > 0.f &&
- maxLayerWhitePoint > 0.f && display.targetLuminanceNits > maxLayerWhitePoint
- ? maxLayerWhitePoint / display.targetLuminanceNits
- : 1.f;
-
- // Find if any layers have requested blur, we'll use that info to decide when to render to an
- // offscreen buffer and when to render to the native buffer.
- sk_sp<SkSurface> activeSurface(dstSurface);
- SkCanvas* canvas = dstCanvas;
- SkiaCapture::OffscreenState offscreenCaptureState;
- const LayerSettings* blurCompositionLayer = nullptr;
- if (mBlurFilter) {
- bool requiresCompositionLayer = false;
- for (const auto& layer : layers) {
- // if the layer doesn't have blur or it is not visible then continue
- if (!layerHasBlur(layer, ctModifiesAlpha)) {
- continue;
- }
- if (layer.backgroundBlurRadius > 0 &&
- layer.backgroundBlurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
- requiresCompositionLayer = true;
- }
- for (auto region : layer.blurRegions) {
- if (region.blurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
- requiresCompositionLayer = true;
- }
- }
- if (requiresCompositionLayer) {
- activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
- canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
- blurCompositionLayer = &layer;
- break;
- }
- }
- }
-
- AutoSaveRestore surfaceAutoSaveRestore(canvas);
- // Clear the entire canvas with a transparent black to prevent ghost images.
- canvas->clear(SK_ColorTRANSPARENT);
- initCanvas(canvas, display);
-
- if (kPrintLayerSettings) {
- logSettings(display);
- }
- for (const auto& layer : layers) {
- ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str());
-
- if (kPrintLayerSettings) {
- logSettings(layer);
- }
-
- sk_sp<SkImage> blurInput;
- if (blurCompositionLayer == &layer) {
- LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface);
- LOG_ALWAYS_FATAL_IF(canvas == dstCanvas);
-
- // save a snapshot of the activeSurface to use as input to the blur shaders
- blurInput = activeSurface->makeImageSnapshot();
-
- // blit the offscreen framebuffer into the destination AHB, but only
- // if there are blur regions. backgroundBlurRadius blurs the entire
- // image below, so it can skip this step.
- if (layer.blurRegions.size()) {
- SkPaint paint;
- paint.setBlendMode(SkBlendMode::kSrc);
- if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
- uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
- dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
- String8::format("SurfaceID|%" PRId64, id).c_str(),
- nullptr);
- dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
- } else {
- activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
- }
- }
-
- // assign dstCanvas to canvas and ensure that the canvas state is up to date
- canvas = dstCanvas;
- surfaceAutoSaveRestore.replace(canvas);
- initCanvas(canvas, display);
-
- LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getSaveCount() !=
- dstSurface->getCanvas()->getSaveCount());
- LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getTotalMatrix() !=
- dstSurface->getCanvas()->getTotalMatrix());
-
- // assign dstSurface to activeSurface
- activeSurface = dstSurface;
- }
-
- SkAutoCanvasRestore layerAutoSaveRestore(canvas, true);
- if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
- // Record the name of the layer if the capture is running.
- std::stringstream layerSettings;
- PrintTo(layer, &layerSettings);
- // Store the LayerSettings in additional information.
- canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(),
- SkData::MakeWithCString(layerSettings.str().c_str()));
- }
- // Layers have a local transform that should be applied to them
- canvas->concat(getSkM44(layer.geometry.positionTransform).asM33());
-
- const auto [bounds, roundRectClip] =
- getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop,
- layer.geometry.roundedCornersRadius);
- if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) {
- std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
-
- // if multiple layers have blur, then we need to take a snapshot now because
- // only the lowest layer will have blurImage populated earlier
- if (!blurInput) {
- blurInput = activeSurface->makeImageSnapshot();
- }
- // rect to be blurred in the coordinate space of blurInput
- const auto blurRect = canvas->getTotalMatrix().mapRect(bounds.rect());
-
- // if the clip needs to be applied then apply it now and make sure
- // it is restored before we attempt to draw any shadows.
- SkAutoCanvasRestore acr(canvas, true);
- if (!roundRectClip.isEmpty()) {
- canvas->clipRRect(roundRectClip, true);
- }
-
- // TODO(b/182216890): Filter out empty layers earlier
- if (blurRect.width() > 0 && blurRect.height() > 0) {
- if (layer.backgroundBlurRadius > 0) {
- ATRACE_NAME("BackgroundBlur");
- auto blurredImage = mBlurFilter->generate(grContext, layer.backgroundBlurRadius,
- blurInput, blurRect);
-
- cachedBlurs[layer.backgroundBlurRadius] = blurredImage;
-
- mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f,
- blurRect, blurredImage, blurInput);
- }
-
- canvas->concat(getSkM44(layer.blurRegionTransform).asM33());
- for (auto region : layer.blurRegions) {
- if (cachedBlurs[region.blurRadius] == nullptr) {
- ATRACE_NAME("BlurRegion");
- cachedBlurs[region.blurRadius] =
- mBlurFilter->generate(grContext, region.blurRadius, blurInput,
- blurRect);
- }
-
- mBlurFilter->drawBlurRegion(canvas, getBlurRRect(region), region.blurRadius,
- region.alpha, blurRect,
- cachedBlurs[region.blurRadius], blurInput);
- }
- }
- }
-
- if (layer.shadow.length > 0) {
- // This would require a new parameter/flag to SkShadowUtils::DrawShadow
- LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow");
-
- SkRRect shadowBounds, shadowClip;
- if (layer.geometry.boundaries == layer.shadow.boundaries) {
- shadowBounds = bounds;
- shadowClip = roundRectClip;
- } else {
- std::tie(shadowBounds, shadowClip) =
- getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop,
- layer.geometry.roundedCornersRadius);
- }
-
- // Technically, if bounds is a rect and roundRectClip is not empty,
- // it means that the bounds and roundedCornersCrop were different
- // enough that we should intersect them to find the proper shadow.
- // In practice, this often happens when the two rectangles appear to
- // not match due to rounding errors. Draw the rounded version, which
- // looks more like the intent.
- const auto& rrect =
- shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds;
- drawShadow(canvas, rrect, layer.shadow);
- }
-
- const float layerDimmingRatio = layer.whitePointNits <= 0.f
- ? displayDimmingRatio
- : (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio;
-
- const bool dimInLinearSpace = display.dimmingStage !=
- aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
-
- const bool requiresLinearEffect = layer.colorTransform != mat4() ||
- (mUseColorManagement &&
- needsToneMapping(layer.sourceDataspace, display.outputDataspace)) ||
- (dimInLinearSpace && !equalsWithinMargin(1.f, layerDimmingRatio));
-
- // quick abort from drawing the remaining portion of the layer
- if (layer.skipContentDraw ||
- (layer.alpha == 0 && !requiresLinearEffect && !layer.disableBlending &&
- (!displayColorTransform || displayColorTransform->isAlphaUnchanged()))) {
- continue;
- }
-
- // If we need to map to linear space or color management is disabled, then mark the source
- // image with the same colorspace as the destination surface so that Skia's color
- // management is a no-op.
- const ui::Dataspace layerDataspace = (!mUseColorManagement || requiresLinearEffect)
- ? dstDataspace
- : layer.sourceDataspace;
-
- SkPaint paint;
- if (layer.source.buffer.buffer) {
- ATRACE_NAME("DrawImage");
- validateInputBufferUsage(layer.source.buffer.buffer->getBuffer());
- const auto& item = layer.source.buffer;
- std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr;
-
- if (const auto& iter = cache.find(item.buffer->getBuffer()->getId());
- iter != cache.end()) {
- imageTextureRef = iter->second;
- } else {
- // If we didn't find the image in the cache, then create a local ref but don't cache
- // it. If we're using skia, we're guaranteed to run on a dedicated GPU thread so if
- // we didn't find anything in the cache then we intentionally did not cache this
- // buffer's resources.
- imageTextureRef = std::make_shared<
- AutoBackendTexture::LocalRef>(grContext,
- item.buffer->getBuffer()->toAHardwareBuffer(),
- false, mTextureCleanupMgr);
- }
-
- // if the layer's buffer has a fence, then we must must respect the fence prior to using
- // the buffer.
- if (layer.source.buffer.fence != nullptr) {
- waitFence(layer.source.buffer.fence->get());
- }
-
- // isOpaque means we need to ignore the alpha in the image,
- // replacing it with the alpha specified by the LayerSettings. See
- // https://developer.android.com/reference/android/view/SurfaceControl.Builder#setOpaque(boolean)
- // The proper way to do this is to use an SkColorType that ignores
- // alpha, like kRGB_888x_SkColorType, and that is used if the
- // incoming image is kRGBA_8888_SkColorType. However, the incoming
- // image may be kRGBA_F16_SkColorType, for which there is no RGBX
- // SkColorType, or kRGBA_1010102_SkColorType, for which we have
- // kRGB_101010x_SkColorType, but it is not yet supported as a source
- // on the GPU. (Adding both is tracked in skbug.com/12048.) In the
- // meantime, we'll use a workaround that works unless we need to do
- // any color conversion. The workaround requires that we pretend the
- // image is already premultiplied, so that we do not premultiply it
- // before applying SkBlendMode::kPlus.
- const bool useIsOpaqueWorkaround = item.isOpaque &&
- (imageTextureRef->colorType() == kRGBA_1010102_SkColorType ||
- imageTextureRef->colorType() == kRGBA_F16_SkColorType);
- const auto alphaType = useIsOpaqueWorkaround ? kPremul_SkAlphaType
- : item.isOpaque ? kOpaque_SkAlphaType
- : item.usePremultipliedAlpha ? kPremul_SkAlphaType
- : kUnpremul_SkAlphaType;
- sk_sp<SkImage> image = imageTextureRef->makeImage(layerDataspace, alphaType, grContext);
-
- auto texMatrix = getSkM44(item.textureTransform).asM33();
- // textureTansform was intended to be passed directly into a shader, so when
- // building the total matrix with the textureTransform we need to first
- // normalize it, then apply the textureTransform, then scale back up.
- texMatrix.preScale(1.0f / bounds.width(), 1.0f / bounds.height());
- texMatrix.postScale(image->width(), image->height());
-
- SkMatrix matrix;
- if (!texMatrix.invert(&matrix)) {
- matrix = texMatrix;
- }
- // The shader does not respect the translation, so we add it to the texture
- // transform for the SkImage. This will make sure that the correct layer contents
- // are drawn in the correct part of the screen.
- matrix.postTranslate(bounds.rect().fLeft, bounds.rect().fTop);
-
- sk_sp<SkShader> shader;
-
- if (layer.source.buffer.useTextureFiltering) {
- shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
- SkSamplingOptions(
- {SkFilterMode::kLinear, SkMipmapMode::kNone}),
- &matrix);
- } else {
- shader = image->makeShader(SkSamplingOptions(), matrix);
- }
-
- if (useIsOpaqueWorkaround) {
- shader = SkShaders::Blend(SkBlendMode::kPlus, shader,
- SkShaders::Color(SkColors::kBlack,
- toSkColorSpace(layerDataspace)));
- }
-
- paint.setShader(createRuntimeEffectShader(
- RuntimeEffectShaderParameters{.shader = shader,
- .layer = layer,
- .display = display,
- .undoPremultipliedAlpha = !item.isOpaque &&
- item.usePremultipliedAlpha,
- .requiresLinearEffect = requiresLinearEffect,
- .layerDimmingRatio = dimInLinearSpace
- ? layerDimmingRatio
- : 1.f}));
-
- // Turn on dithering when dimming beyond this (arbitrary) threshold...
- static constexpr float kDimmingThreshold = 0.2f;
- // ...or we're rendering an HDR layer down to an 8-bit target
- // Most HDR standards require at least 10-bits of color depth for source content, so we
- // can just extract the transfer function rather than dig into precise gralloc layout.
- // Furthermore, we can assume that the only 8-bit target we support is RGBA8888.
- const bool requiresDownsample = isHdrDataspace(layer.sourceDataspace) &&
- buffer->getPixelFormat() == PIXEL_FORMAT_RGBA_8888;
- if (layerDimmingRatio <= kDimmingThreshold || requiresDownsample) {
- paint.setDither(true);
- }
- paint.setAlphaf(layer.alpha);
-
- if (imageTextureRef->colorType() == kAlpha_8_SkColorType) {
- LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with A8");
-
- // SysUI creates the alpha layer as a coverage layer, which is
- // appropriate for the DPU. Use a color matrix to convert it to
- // a mask.
- // TODO (b/219525258): Handle input as a mask.
- //
- // The color matrix will convert A8 pixels with no alpha to
- // black, as described by this vector. If the display handles
- // the color transform, we need to invert it to find the color
- // that will result in black after the DPU applies the transform.
- SkV4 black{0.0f, 0.0f, 0.0f, 1.0f}; // r, g, b, a
- if (display.colorTransform != mat4() && display.deviceHandlesColorTransform) {
- SkM44 colorSpaceMatrix = getSkM44(display.colorTransform);
- if (colorSpaceMatrix.invert(&colorSpaceMatrix)) {
- black = colorSpaceMatrix * black;
- } else {
- // We'll just have to use 0,0,0 as black, which should
- // be close to correct.
- ALOGI("Could not invert colorTransform!");
- }
- }
- SkColorMatrix colorMatrix(0, 0, 0, 0, black[0],
- 0, 0, 0, 0, black[1],
- 0, 0, 0, 0, black[2],
- 0, 0, 0, -1, 1);
- if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
- // On the other hand, if the device doesn't handle it, we
- // have to apply it ourselves.
- colorMatrix.postConcat(toSkColorMatrix(display.colorTransform));
- }
- paint.setColorFilter(SkColorFilters::Matrix(colorMatrix));
- }
- } else {
- ATRACE_NAME("DrawColor");
- const auto color = layer.source.solidColor;
- sk_sp<SkShader> shader = SkShaders::Color(SkColor4f{.fR = color.r,
- .fG = color.g,
- .fB = color.b,
- .fA = layer.alpha},
- toSkColorSpace(layerDataspace));
- paint.setShader(createRuntimeEffectShader(
- RuntimeEffectShaderParameters{.shader = shader,
- .layer = layer,
- .display = display,
- .undoPremultipliedAlpha = false,
- .requiresLinearEffect = requiresLinearEffect,
- .layerDimmingRatio = layerDimmingRatio}));
- }
-
- if (layer.disableBlending) {
- paint.setBlendMode(SkBlendMode::kSrc);
- }
-
- // An A8 buffer will already have the proper color filter attached to
- // its paint, including the displayColorTransform as needed.
- if (!paint.getColorFilter()) {
- if (!dimInLinearSpace && !equalsWithinMargin(1.0, layerDimmingRatio)) {
- // If we don't dim in linear space, then when we gamma correct the dimming ratio we
- // can assume a gamma 2.2 transfer function.
- static constexpr float kInverseGamma22 = 1.f / 2.2f;
- const auto gammaCorrectedDimmingRatio =
- std::pow(layerDimmingRatio, kInverseGamma22);
- auto dimmingMatrix =
- mat4::scale(vec4(gammaCorrectedDimmingRatio, gammaCorrectedDimmingRatio,
- gammaCorrectedDimmingRatio, 1.f));
-
- const auto colorFilter =
- SkColorFilters::Matrix(toSkColorMatrix(std::move(dimmingMatrix)));
- paint.setColorFilter(displayColorTransform
- ? displayColorTransform->makeComposed(colorFilter)
- : colorFilter);
- } else {
- paint.setColorFilter(displayColorTransform);
- }
- }
-
- if (!roundRectClip.isEmpty()) {
- canvas->clipRRect(roundRectClip, true);
- }
-
- if (!bounds.isRect()) {
- paint.setAntiAlias(true);
- canvas->drawRRect(bounds, paint);
- } else {
- canvas->drawRect(bounds.rect(), paint);
- }
- if (kFlushAfterEveryLayer) {
- ATRACE_NAME("flush surface");
- activeSurface->flush();
- }
- }
- for (const auto& borderRenderInfo : display.borderInfoList) {
- SkPaint p;
- p.setColor(SkColor4f{borderRenderInfo.color.r, borderRenderInfo.color.g,
- borderRenderInfo.color.b, borderRenderInfo.color.a});
- p.setAntiAlias(true);
- p.setStyle(SkPaint::kStroke_Style);
- p.setStrokeWidth(borderRenderInfo.width);
- SkRegion sk_region;
- SkPath path;
-
- // Construct a final SkRegion using Regions
- for (const auto& r : borderRenderInfo.combinedRegion) {
- sk_region.op({r.left, r.top, r.right, r.bottom}, SkRegion::kUnion_Op);
- }
-
- sk_region.getBoundaryPath(&path);
- canvas->drawPath(path, p);
- path.close();
- }
-
- surfaceAutoSaveRestore.restore();
- mCapture->endCapture();
- {
- ATRACE_NAME("flush surface");
- LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface);
- activeSurface->flush();
- }
-
- base::unique_fd drawFence = flush();
-
- // If flush failed or we don't support native fences, we need to force the
- // gl command stream to be executed.
- bool requireSync = drawFence.get() < 0;
- if (requireSync) {
- ATRACE_BEGIN("Submit(sync=true)");
- } else {
- ATRACE_BEGIN("Submit(sync=false)");
- }
- bool success = grContext->submit(requireSync);
- ATRACE_END();
- if (!success) {
- ALOGE("Failed to flush RenderEngine commands");
- // Chances are, something illegal happened (either the caller passed
- // us bad parameters, or we messed up our shader generation).
- resultPromise->set_value({INVALID_OPERATION, std::move(drawFence)});
- return;
- }
-
- // checkErrors();
- resultPromise->set_value({NO_ERROR, std::move(drawFence)});
- return;
-}
-
-inline SkRect SkiaGLRenderEngine::getSkRect(const FloatRect& rect) {
- return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
-}
-
-inline SkRect SkiaGLRenderEngine::getSkRect(const Rect& rect) {
- return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
-}
-
-/**
- * Verifies that common, simple bounds + clip combinations can be converted into
- * a single RRect draw call returning true if possible. If true the radii parameter
- * will be filled with the correct radii values that combined with bounds param will
- * produce the insected roundRect. If false, the returned state of the radii param is undefined.
- */
-static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
- const SkRect& insetCrop, const vec2& cornerRadius,
- SkVector radii[4]) {
- const bool leftEqual = bounds.fLeft == crop.fLeft;
- const bool topEqual = bounds.fTop == crop.fTop;
- const bool rightEqual = bounds.fRight == crop.fRight;
- const bool bottomEqual = bounds.fBottom == crop.fBottom;
-
- // In the event that the corners of the bounds only partially align with the crop we
- // need to ensure that the resulting shape can still be represented as a round rect.
- // In particular the round rect implementation will scale the value of all corner radii
- // if the sum of the radius along any edge is greater than the length of that edge.
- // See https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
- const bool requiredWidth = bounds.width() > (cornerRadius.x * 2);
- const bool requiredHeight = bounds.height() > (cornerRadius.y * 2);
- if (!requiredWidth || !requiredHeight) {
- return false;
- }
-
- // Check each cropped corner to ensure that it exactly matches the crop or its corner is
- // contained within the cropped shape and does not need rounded.
- // compute the UpperLeft corner radius
- if (leftEqual && topEqual) {
- radii[0].set(cornerRadius.x, cornerRadius.y);
- } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) ||
- (topEqual && bounds.fLeft >= insetCrop.fLeft)) {
- radii[0].set(0, 0);
- } else {
- return false;
- }
- // compute the UpperRight corner radius
- if (rightEqual && topEqual) {
- radii[1].set(cornerRadius.x, cornerRadius.y);
- } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) ||
- (topEqual && bounds.fRight <= insetCrop.fRight)) {
- radii[1].set(0, 0);
- } else {
- return false;
- }
- // compute the BottomRight corner radius
- if (rightEqual && bottomEqual) {
- radii[2].set(cornerRadius.x, cornerRadius.y);
- } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) ||
- (bottomEqual && bounds.fRight <= insetCrop.fRight)) {
- radii[2].set(0, 0);
- } else {
- return false;
- }
- // compute the BottomLeft corner radius
- if (leftEqual && bottomEqual) {
- radii[3].set(cornerRadius.x, cornerRadius.y);
- } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) ||
- (bottomEqual && bounds.fLeft >= insetCrop.fLeft)) {
- radii[3].set(0, 0);
- } else {
- return false;
- }
-
- return true;
-}
-
-inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const FloatRect& boundsRect,
- const FloatRect& cropRect,
- const vec2& cornerRadius) {
- const SkRect bounds = getSkRect(boundsRect);
- const SkRect crop = getSkRect(cropRect);
-
- SkRRect clip;
- if (cornerRadius.x > 0 && cornerRadius.y > 0) {
- // it the crop and the bounds are equivalent or there is no crop then we don't need a clip
- if (bounds == crop || crop.isEmpty()) {
- return {SkRRect::MakeRectXY(bounds, cornerRadius.x, cornerRadius.y), clip};
- }
-
- // This makes an effort to speed up common, simple bounds + clip combinations by
- // converting them to a single RRect draw. It is possible there are other cases
- // that can be converted.
- if (crop.contains(bounds)) {
- const auto insetCrop = crop.makeInset(cornerRadius.x, cornerRadius.y);
- if (insetCrop.contains(bounds)) {
- return {SkRRect::MakeRect(bounds), clip}; // clip is empty - no rounding required
- }
-
- SkVector radii[4];
- if (intersectionIsRoundRect(bounds, crop, insetCrop, cornerRadius, radii)) {
- SkRRect intersectionBounds;
- intersectionBounds.setRectRadii(bounds, radii);
- return {intersectionBounds, clip};
- }
- }
-
- // we didn't hit any of our fast paths so set the clip to the cropRect
- clip.setRectXY(crop, cornerRadius.x, cornerRadius.y);
- }
-
- // if we hit this point then we either don't have rounded corners or we are going to rely
- // on the clip to round the corners for us
- return {SkRRect::MakeRect(bounds), clip};
-}
-
-inline bool SkiaGLRenderEngine::layerHasBlur(const LayerSettings& layer,
- bool colorTransformModifiesAlpha) {
- if (layer.backgroundBlurRadius > 0 || layer.blurRegions.size()) {
- // return false if the content is opaque and would therefore occlude the blur
- const bool opaqueContent = !layer.source.buffer.buffer || layer.source.buffer.isOpaque;
- const bool opaqueAlpha = layer.alpha == 1.0f && !colorTransformModifiesAlpha;
- return layer.skipContentDraw || !(opaqueContent && opaqueAlpha);
- }
- return false;
-}
-
-inline SkColor SkiaGLRenderEngine::getSkColor(const vec4& color) {
- return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255);
-}
-
-inline SkM44 SkiaGLRenderEngine::getSkM44(const mat4& matrix) {
- return SkM44(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],
- matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],
- matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],
- matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
-}
-
-inline SkPoint3 SkiaGLRenderEngine::getSkPoint3(const vec3& vector) {
- return SkPoint3::Make(vector.x, vector.y, vector.z);
-}
-
-size_t SkiaGLRenderEngine::getMaxTextureSize() const {
- return mGrContext->maxTextureSize();
-}
-
-size_t SkiaGLRenderEngine::getMaxViewportDims() const {
- return mGrContext->maxRenderTargetSize();
-}
-
-void SkiaGLRenderEngine::drawShadow(SkCanvas* canvas, const SkRRect& casterRRect,
- const ShadowSettings& settings) {
- ATRACE_CALL();
- const float casterZ = settings.length / 2.0f;
- const auto flags =
- settings.casterIsTranslucent ? kTransparentOccluder_ShadowFlag : kNone_ShadowFlag;
-
- SkShadowUtils::DrawShadow(canvas, SkPath::RRect(casterRRect), SkPoint3::Make(0, 0, casterZ),
- getSkPoint3(settings.lightPos), settings.lightRadius,
- getSkColor(settings.ambientColor), getSkColor(settings.spotColor),
- flags);
+ return fenceFd;
}
EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
@@ -1570,114 +519,14 @@
return value;
}
-void SkiaGLRenderEngine::onActiveDisplaySizeChanged(ui::Size size) {
- // This cache multiplier was selected based on review of cache sizes relative
- // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x),
- // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a
- // conservative default based on that analysis.
- const float SURFACE_SIZE_MULTIPLIER = 3.5f * bytesPerPixel(mDefaultPixelFormat);
- const int maxResourceBytes = size.width * size.height * SURFACE_SIZE_MULTIPLIER;
-
- // start by resizing the current context
- getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
-
- // if it is possible to switch contexts then we will resize the other context
- const bool originalProtectedState = mInProtectedContext;
- useProtectedContext(!mInProtectedContext);
- if (mInProtectedContext != originalProtectedState) {
- getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
- // reset back to the initial context that was active when this method was called
- useProtectedContext(originalProtectedState);
- }
-}
-
-void SkiaGLRenderEngine::dump(std::string& result) {
+void SkiaGLRenderEngine::appendBackendSpecificInfoToDump(std::string& result) {
const gl::GLExtensions& extensions = gl::GLExtensions::getInstance();
-
- StringAppendF(&result, "\n ------------RE-----------------\n");
+ StringAppendF(&result, "\n ------------RE GLES------------\n");
StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion());
StringAppendF(&result, "%s\n", extensions.getEGLExtensions());
StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
extensions.getVersion());
StringAppendF(&result, "%s\n", extensions.getExtensions());
- StringAppendF(&result, "RenderEngine supports protected context: %d\n",
- supportsProtectedContent());
- StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext);
- StringAppendF(&result, "RenderEngine shaders cached since last dump/primeCache: %d\n",
- mSkSLCacheMonitor.shadersCachedSinceLastCall());
-
- std::vector<ResourcePair> cpuResourceMap = {
- {"skia/sk_resource_cache/bitmap_", "Bitmaps"},
- {"skia/sk_resource_cache/rrect-blur_", "Masks"},
- {"skia/sk_resource_cache/rects-blur_", "Masks"},
- {"skia/sk_resource_cache/tessellated", "Shadows"},
- {"skia", "Other"},
- };
- SkiaMemoryReporter cpuReporter(cpuResourceMap, false);
- SkGraphics::DumpMemoryStatistics(&cpuReporter);
- StringAppendF(&result, "Skia CPU Caches: ");
- cpuReporter.logTotals(result);
- cpuReporter.logOutput(result);
-
- {
- std::lock_guard<std::mutex> lock(mRenderingMutex);
-
- std::vector<ResourcePair> gpuResourceMap = {
- {"texture_renderbuffer", "Texture/RenderBuffer"},
- {"texture", "Texture"},
- {"gr_text_blob_cache", "Text"},
- {"skia", "Other"},
- };
- SkiaMemoryReporter gpuReporter(gpuResourceMap, true);
- mGrContext->dumpMemoryStatistics(&gpuReporter);
- StringAppendF(&result, "Skia's GPU Caches: ");
- gpuReporter.logTotals(result);
- gpuReporter.logOutput(result);
- StringAppendF(&result, "Skia's Wrapped Objects:\n");
- gpuReporter.logOutput(result, true);
-
- StringAppendF(&result, "RenderEngine tracked buffers: %zu\n",
- mGraphicBufferExternalRefs.size());
- StringAppendF(&result, "Dumping buffer ids...\n");
- for (const auto& [id, refCounts] : mGraphicBufferExternalRefs) {
- StringAppendF(&result, "- 0x%" PRIx64 " - %d refs \n", id, refCounts);
- }
- StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n",
- mTextureCache.size());
- StringAppendF(&result, "Dumping buffer ids...\n");
- // TODO(178539829): It would be nice to know which layer these are coming from and what
- // the texture sizes are.
- for (const auto& [id, unused] : mTextureCache) {
- StringAppendF(&result, "- 0x%" PRIx64 "\n", id);
- }
- StringAppendF(&result, "\n");
-
- SkiaMemoryReporter gpuProtectedReporter(gpuResourceMap, true);
- if (mProtectedGrContext) {
- mProtectedGrContext->dumpMemoryStatistics(&gpuProtectedReporter);
- }
- StringAppendF(&result, "Skia's GPU Protected Caches: ");
- gpuProtectedReporter.logTotals(result);
- gpuProtectedReporter.logOutput(result);
- StringAppendF(&result, "Skia's Protected Wrapped Objects:\n");
- gpuProtectedReporter.logOutput(result, true);
-
- StringAppendF(&result, "\n");
- StringAppendF(&result, "RenderEngine runtime effects: %zu\n", mRuntimeEffects.size());
- for (const auto& [linearEffect, unused] : mRuntimeEffects) {
- StringAppendF(&result, "- inputDataspace: %s\n",
- dataspaceDetails(
- static_cast<android_dataspace>(linearEffect.inputDataspace))
- .c_str());
- StringAppendF(&result, "- outputDataspace: %s\n",
- dataspaceDetails(
- static_cast<android_dataspace>(linearEffect.outputDataspace))
- .c_str());
- StringAppendF(&result, "undoPremultipliedAlpha: %s\n",
- linearEffect.undoPremultipliedAlpha ? "true" : "false");
- }
- }
- StringAppendF(&result, "\n");
}
} // namespace skia
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 34f18c1..4a37ffe 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -55,33 +55,23 @@
SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLContext ctxt,
EGLSurface placeholder, EGLContext protectedContext,
EGLSurface protectedPlaceholder);
- ~SkiaGLRenderEngine() override EXCLUDES(mRenderingMutex);
+ ~SkiaGLRenderEngine() override;
- std::future<void> primeCache() override;
- void cleanupPostRender() override;
- void cleanFramebufferCache() override{};
int getContextPriority() override;
- bool isProtected() const override { return mInProtectedContext; }
- bool supportsProtectedContent() const override;
- void useProtectedContext(bool useProtectedContext) override;
- bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; }
- void onActiveDisplaySizeChanged(ui::Size size) override;
- int reportShadersCompiled() override;
protected:
- void dump(std::string& result) override;
- size_t getMaxTextureSize() const override;
- size_t getMaxViewportDims() const override;
- void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer, bool isRenderable) override;
- void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override;
- bool canSkipPostRenderCleanup() const override;
- void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
- const DisplaySettings& display,
- const std::vector<LayerSettings>& layers,
- const std::shared_ptr<ExternalTexture>& buffer,
- const bool useFramebufferCache, base::unique_fd&& bufferFence) override;
+ // Implementations of abstract SkiaRenderEngine functions specific to
+ // rendering backend
+ virtual SkiaRenderEngine::Contexts createDirectContexts(const GrContextOptions& options);
+ bool supportsProtectedContentImpl() const override;
+ bool useProtectedContextImpl(GrProtected isProtected) override;
+ void waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) override;
+ base::unique_fd flushAndSubmit(GrDirectContext* context) override;
+ void appendBackendSpecificInfoToDump(std::string& result) override;
private:
+ bool waitGpuFence(base::borrowed_fd fenceFd);
+ base::unique_fd flush();
static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
static EGLContext createEglContext(EGLDisplay display, EGLConfig config,
EGLContext shareContext,
@@ -89,107 +79,14 @@
Protection protection);
static std::optional<RenderEngine::ContextPriority> createContextPriority(
const RenderEngineCreationArgs& args);
- static EGLSurface createPlaceholderEglPbufferSurface(EGLDisplay display, EGLConfig config,
- int hwcFormat, Protection protection);
- inline SkRect getSkRect(const FloatRect& layer);
- inline SkRect getSkRect(const Rect& layer);
- inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const FloatRect& bounds,
- const FloatRect& crop,
- const vec2& cornerRadius);
- inline bool layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha);
- inline SkColor getSkColor(const vec4& color);
- inline SkM44 getSkM44(const mat4& matrix);
- inline SkPoint3 getSkPoint3(const vec3& vector);
- inline GrDirectContext* getActiveGrContext() const;
-
- base::unique_fd flush();
- // waitFence attempts to wait in the GPU, and if unable to waits on the CPU instead.
- void waitFence(base::borrowed_fd fenceFd);
- bool waitGpuFence(base::borrowed_fd fenceFd);
-
- void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
- void drawShadow(SkCanvas* canvas, const SkRRect& casterRRect,
- const ShadowSettings& shadowSettings);
-
- // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned.
- // Otherwise it returns the input shader.
- struct RuntimeEffectShaderParameters {
- sk_sp<SkShader> shader;
- const LayerSettings& layer;
- const DisplaySettings& display;
- bool undoPremultipliedAlpha;
- bool requiresLinearEffect;
- float layerDimmingRatio;
- };
- sk_sp<SkShader> createRuntimeEffectShader(const RuntimeEffectShaderParameters&);
+ static EGLSurface createPlaceholderEglPbufferSurface(
+ EGLDisplay display, EGLConfig config, int hwcFormat, Protection protection);
EGLDisplay mEGLDisplay;
EGLContext mEGLContext;
EGLSurface mPlaceholderSurface;
EGLContext mProtectedEGLContext;
EGLSurface mProtectedPlaceholderSurface;
- BlurFilter* mBlurFilter = nullptr;
-
- const PixelFormat mDefaultPixelFormat;
- const bool mUseColorManagement;
-
- // Identifier used or various mappings of layers to various
- // textures or shaders
- using GraphicBufferId = uint64_t;
-
- // Number of external holders of ExternalTexture references, per GraphicBuffer ID.
- std::unordered_map<GraphicBufferId, int32_t> mGraphicBufferExternalRefs
- GUARDED_BY(mRenderingMutex);
- // Cache of GL textures that we'll store per GraphicBuffer ID, shared between GPU contexts.
- std::unordered_map<GraphicBufferId, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache
- GUARDED_BY(mRenderingMutex);
- std::unordered_map<shaders::LinearEffect, sk_sp<SkRuntimeEffect>, shaders::LinearEffectHasher>
- mRuntimeEffects;
- AutoBackendTexture::CleanupManager mTextureCleanupMgr GUARDED_BY(mRenderingMutex);
-
- StretchShaderFactory mStretchShaderFactory;
- // Mutex guarding rendering operations, so that:
- // 1. GL operations aren't interleaved, and
- // 2. Internal state related to rendering that is potentially modified by
- // multiple threads is guaranteed thread-safe.
- mutable std::mutex mRenderingMutex;
-
- sp<Fence> mLastDrawFence;
-
- // Graphics context used for creating surfaces and submitting commands
- sk_sp<GrDirectContext> mGrContext;
- // Same as above, but for protected content (eg. DRM)
- sk_sp<GrDirectContext> mProtectedGrContext;
-
- bool mInProtectedContext = false;
- // Object to capture commands send to Skia.
- std::unique_ptr<SkiaCapture> mCapture;
-
- // Implements PersistentCache as a way to monitor what SkSL shaders Skia has
- // cached.
- class SkSLCacheMonitor : public GrContextOptions::PersistentCache {
- public:
- SkSLCacheMonitor() = default;
- ~SkSLCacheMonitor() override = default;
-
- sk_sp<SkData> load(const SkData& key) override;
-
- void store(const SkData& key, const SkData& data, const SkString& description) override;
-
- int shadersCachedSinceLastCall() {
- const int shadersCachedSinceLastCall = mShadersCachedSinceLastCall;
- mShadersCachedSinceLastCall = 0;
- return shadersCachedSinceLastCall;
- }
-
- int totalShadersCompiled() const { return mTotalShadersCompiled; }
-
- private:
- int mShadersCachedSinceLastCall = 0;
- int mTotalShadersCompiled = 0;
- };
-
- SkSLCacheMonitor mSkSLCacheMonitor;
};
} // namespace skia
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index 1fb24f5..db983a8 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -20,16 +20,1244 @@
#include "SkiaRenderEngine.h"
+#include <GrBackendSemaphore.h>
+#include <GrContextOptions.h>
+#include <SkBlendMode.h>
+#include <SkCanvas.h>
+#include <SkColor.h>
+#include <SkColorFilter.h>
+#include <SkColorMatrix.h>
+#include <SkColorSpace.h>
+#include <SkData.h>
+#include <SkGraphics.h>
+#include <SkImage.h>
+#include <SkImageFilters.h>
+#include <SkImageInfo.h>
+#include <SkM44.h>
+#include <SkMatrix.h>
+#include <SkPaint.h>
+#include <SkPath.h>
+#include <SkPoint.h>
+#include <SkPoint3.h>
+#include <SkRect.h>
+#include <SkRefCnt.h>
+#include <SkRegion.h>
+#include <SkRRect.h>
+#include <SkRuntimeEffect.h>
+#include <SkSamplingOptions.h>
+#include <SkScalar.h>
+#include <SkShader.h>
+#include <SkShadowUtils.h>
+#include <SkString.h>
+#include <SkSurface.h>
+#include <SkTileMode.h>
#include <src/core/SkTraceEventCommon.h>
+#include <android-base/stringprintf.h>
+#include <gui/TraceUtils.h>
+#include <sync/sync.h>
+#include <ui/BlurRegion.h>
+#include <ui/DataspaceUtils.h>
+#include <ui/DebugUtils.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Trace.h>
+
+#include <cmath>
+#include <cstdint>
+#include <memory>
+#include <numeric>
+
+#include "Cache.h"
+#include "ColorSpaces.h"
+#include "filters/BlurFilter.h"
+#include "filters/GaussianBlurFilter.h"
+#include "filters/KawaseBlurFilter.h"
+#include "filters/LinearEffect.h"
+#include "log/log_main.h"
+#include "skia/debug/SkiaCapture.h"
+#include "skia/debug/SkiaMemoryReporter.h"
+#include "skia/filters/StretchShaderFactory.h"
+#include "system/graphics-base-v1.0.h"
+
+namespace {
+
+// Debugging settings
+static const bool kPrintLayerSettings = false;
+static const bool kFlushAfterEveryLayer = kPrintLayerSettings;
+
+} // namespace
+
+// Utility functions related to SkRect
+
+namespace {
+
+static inline SkRect getSkRect(const android::FloatRect& rect) {
+ return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
+}
+
+static inline SkRect getSkRect(const android::Rect& rect) {
+ return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
+}
+
+/**
+ * Verifies that common, simple bounds + clip combinations can be converted into
+ * a single RRect draw call returning true if possible. If true the radii parameter
+ * will be filled with the correct radii values that combined with bounds param will
+ * produce the insected roundRect. If false, the returned state of the radii param is undefined.
+ */
+static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop,
+ const SkRect& insetCrop, const android::vec2& cornerRadius,
+ SkVector radii[4]) {
+ const bool leftEqual = bounds.fLeft == crop.fLeft;
+ const bool topEqual = bounds.fTop == crop.fTop;
+ const bool rightEqual = bounds.fRight == crop.fRight;
+ const bool bottomEqual = bounds.fBottom == crop.fBottom;
+
+ // In the event that the corners of the bounds only partially align with the crop we
+ // need to ensure that the resulting shape can still be represented as a round rect.
+ // In particular the round rect implementation will scale the value of all corner radii
+ // if the sum of the radius along any edge is greater than the length of that edge.
+ // See https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
+ const bool requiredWidth = bounds.width() > (cornerRadius.x * 2);
+ const bool requiredHeight = bounds.height() > (cornerRadius.y * 2);
+ if (!requiredWidth || !requiredHeight) {
+ return false;
+ }
+
+ // Check each cropped corner to ensure that it exactly matches the crop or its corner is
+ // contained within the cropped shape and does not need rounded.
+ // compute the UpperLeft corner radius
+ if (leftEqual && topEqual) {
+ radii[0].set(cornerRadius.x, cornerRadius.y);
+ } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) ||
+ (topEqual && bounds.fLeft >= insetCrop.fLeft)) {
+ radii[0].set(0, 0);
+ } else {
+ return false;
+ }
+ // compute the UpperRight corner radius
+ if (rightEqual && topEqual) {
+ radii[1].set(cornerRadius.x, cornerRadius.y);
+ } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) ||
+ (topEqual && bounds.fRight <= insetCrop.fRight)) {
+ radii[1].set(0, 0);
+ } else {
+ return false;
+ }
+ // compute the BottomRight corner radius
+ if (rightEqual && bottomEqual) {
+ radii[2].set(cornerRadius.x, cornerRadius.y);
+ } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) ||
+ (bottomEqual && bounds.fRight <= insetCrop.fRight)) {
+ radii[2].set(0, 0);
+ } else {
+ return false;
+ }
+ // compute the BottomLeft corner radius
+ if (leftEqual && bottomEqual) {
+ radii[3].set(cornerRadius.x, cornerRadius.y);
+ } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) ||
+ (bottomEqual && bounds.fLeft >= insetCrop.fLeft)) {
+ radii[3].set(0, 0);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+static inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const android::FloatRect& boundsRect,
+ const android::FloatRect& cropRect,
+ const android::vec2& cornerRadius) {
+ const SkRect bounds = getSkRect(boundsRect);
+ const SkRect crop = getSkRect(cropRect);
+
+ SkRRect clip;
+ if (cornerRadius.x > 0 && cornerRadius.y > 0) {
+ // it the crop and the bounds are equivalent or there is no crop then we don't need a clip
+ if (bounds == crop || crop.isEmpty()) {
+ return {SkRRect::MakeRectXY(bounds, cornerRadius.x, cornerRadius.y), clip};
+ }
+
+ // This makes an effort to speed up common, simple bounds + clip combinations by
+ // converting them to a single RRect draw. It is possible there are other cases
+ // that can be converted.
+ if (crop.contains(bounds)) {
+ const auto insetCrop = crop.makeInset(cornerRadius.x, cornerRadius.y);
+ if (insetCrop.contains(bounds)) {
+ return {SkRRect::MakeRect(bounds), clip}; // clip is empty - no rounding required
+ }
+
+ SkVector radii[4];
+ if (intersectionIsRoundRect(bounds, crop, insetCrop, cornerRadius, radii)) {
+ SkRRect intersectionBounds;
+ intersectionBounds.setRectRadii(bounds, radii);
+ return {intersectionBounds, clip};
+ }
+ }
+
+ // we didn't hit any of our fast paths so set the clip to the cropRect
+ clip.setRectXY(crop, cornerRadius.x, cornerRadius.y);
+ }
+
+ // if we hit this point then we either don't have rounded corners or we are going to rely
+ // on the clip to round the corners for us
+ return {SkRRect::MakeRect(bounds), clip};
+}
+
+static inline bool layerHasBlur(const android::renderengine::LayerSettings& layer,
+ bool colorTransformModifiesAlpha) {
+ if (layer.backgroundBlurRadius > 0 || layer.blurRegions.size()) {
+ // return false if the content is opaque and would therefore occlude the blur
+ const bool opaqueContent = !layer.source.buffer.buffer || layer.source.buffer.isOpaque;
+ const bool opaqueAlpha = layer.alpha == 1.0f && !colorTransformModifiesAlpha;
+ return layer.skipContentDraw || !(opaqueContent && opaqueAlpha);
+ }
+ return false;
+}
+
+static inline SkColor getSkColor(const android::vec4& color) {
+ return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255);
+}
+
+static inline SkM44 getSkM44(const android::mat4& matrix) {
+ return SkM44(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],
+ matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],
+ matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],
+ matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
+}
+
+static inline SkPoint3 getSkPoint3(const android::vec3& vector) {
+ return SkPoint3::Make(vector.x, vector.y, vector.z);
+}
+
+} // namespace
namespace android {
namespace renderengine {
namespace skia {
-SkiaRenderEngine::SkiaRenderEngine(RenderEngineType type) : RenderEngine(type) {}
+
+using base::StringAppendF;
+
+std::future<void> SkiaRenderEngine::primeCache() {
+ Cache::primeShaderCache(this);
+ return {};
+}
+
+sk_sp<SkData> SkiaRenderEngine::SkSLCacheMonitor::load(const SkData& key) {
+ // This "cache" does not actually cache anything. It just allows us to
+ // monitor Skia's internal cache. So this method always returns null.
+ return nullptr;
+}
+
+void SkiaRenderEngine::SkSLCacheMonitor::store(const SkData& key, const SkData& data,
+ const SkString& description) {
+ mShadersCachedSinceLastCall++;
+ mTotalShadersCompiled++;
+ ATRACE_FORMAT("SF cache: %i shaders", mTotalShadersCompiled);
+}
+
+int SkiaRenderEngine::reportShadersCompiled() {
+ return mSkSLCacheMonitor.totalShadersCompiled();
+}
void SkiaRenderEngine::setEnableTracing(bool tracingEnabled) {
SkAndroidFrameworkTraceUtil::setEnableTracing(tracingEnabled);
}
+
+SkiaRenderEngine::SkiaRenderEngine(
+ RenderEngineType type,
+ PixelFormat pixelFormat,
+ bool useColorManagement,
+ bool supportsBackgroundBlur) :
+ RenderEngine(type),
+ mDefaultPixelFormat(pixelFormat),
+ mUseColorManagement(useColorManagement) {
+ if (supportsBackgroundBlur) {
+ ALOGD("Background Blurs Enabled");
+ mBlurFilter = new KawaseBlurFilter();
+ }
+ mCapture = std::make_unique<SkiaCapture>();
+}
+
+SkiaRenderEngine::~SkiaRenderEngine() { }
+
+// To be called from backend dtors.
+void SkiaRenderEngine::finishRenderingAndAbandonContext() {
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+
+ if (mBlurFilter) {
+ delete mBlurFilter;
+ }
+
+ if (mGrContext) {
+ mGrContext->flushAndSubmit(true);
+ mGrContext->abandonContext();
+ }
+
+ if (mProtectedGrContext) {
+ mProtectedGrContext->flushAndSubmit(true);
+ mProtectedGrContext->abandonContext();
+ }
+}
+
+void SkiaRenderEngine::useProtectedContext(bool useProtectedContext) {
+ if (useProtectedContext == mInProtectedContext ||
+ (useProtectedContext && !supportsProtectedContent())) {
+ return;
+ }
+
+ // release any scratch resources before switching into a new mode
+ if (getActiveGrContext()) {
+ getActiveGrContext()->purgeUnlockedResources(true);
+ }
+
+ // Backend-specific way to switch to protected context
+ if (useProtectedContextImpl(
+ useProtectedContext ? GrProtected::kYes : GrProtected::kNo)) {
+ mInProtectedContext = useProtectedContext;
+ // given that we are sharing the same thread between two GrContexts we need to
+ // make sure that the thread state is reset when switching between the two.
+ if (getActiveGrContext()) {
+ getActiveGrContext()->resetContext();
+ }
+ }
+}
+
+GrDirectContext* SkiaRenderEngine::getActiveGrContext() {
+ return mInProtectedContext ? mProtectedGrContext.get() : mGrContext.get();
+}
+
+static float toDegrees(uint32_t transform) {
+ switch (transform) {
+ case ui::Transform::ROT_90:
+ return 90.0;
+ case ui::Transform::ROT_180:
+ return 180.0;
+ case ui::Transform::ROT_270:
+ return 270.0;
+ default:
+ return 0.0;
+ }
+}
+
+static SkColorMatrix toSkColorMatrix(const android::mat4& matrix) {
+ return SkColorMatrix(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0], 0, matrix[0][1],
+ matrix[1][1], matrix[2][1], matrix[3][1], 0, matrix[0][2], matrix[1][2],
+ matrix[2][2], matrix[3][2], 0, matrix[0][3], matrix[1][3], matrix[2][3],
+ matrix[3][3], 0);
+}
+
+static bool needsToneMapping(ui::Dataspace sourceDataspace, ui::Dataspace destinationDataspace) {
+ int64_t sourceTransfer = sourceDataspace & HAL_DATASPACE_TRANSFER_MASK;
+ int64_t destTransfer = destinationDataspace & HAL_DATASPACE_TRANSFER_MASK;
+
+ // Treat unsupported dataspaces as srgb
+ if (destTransfer != HAL_DATASPACE_TRANSFER_LINEAR &&
+ destTransfer != HAL_DATASPACE_TRANSFER_HLG &&
+ destTransfer != HAL_DATASPACE_TRANSFER_ST2084) {
+ destTransfer = HAL_DATASPACE_TRANSFER_SRGB;
+ }
+
+ if (sourceTransfer != HAL_DATASPACE_TRANSFER_LINEAR &&
+ sourceTransfer != HAL_DATASPACE_TRANSFER_HLG &&
+ sourceTransfer != HAL_DATASPACE_TRANSFER_ST2084) {
+ sourceTransfer = HAL_DATASPACE_TRANSFER_SRGB;
+ }
+
+ const bool isSourceLinear = sourceTransfer == HAL_DATASPACE_TRANSFER_LINEAR;
+ const bool isSourceSRGB = sourceTransfer == HAL_DATASPACE_TRANSFER_SRGB;
+ const bool isDestLinear = destTransfer == HAL_DATASPACE_TRANSFER_LINEAR;
+ const bool isDestSRGB = destTransfer == HAL_DATASPACE_TRANSFER_SRGB;
+
+ return !(isSourceLinear && isDestSRGB) && !(isSourceSRGB && isDestLinear) &&
+ sourceTransfer != destTransfer;
+}
+
+void SkiaRenderEngine::ensureGrContextsCreated() {
+ if (mGrContext) {
+ return;
+ }
+
+ GrContextOptions options;
+ options.fDisableDriverCorrectnessWorkarounds = true;
+ options.fDisableDistanceFieldPaths = true;
+ options.fReducedShaderVariations = true;
+ options.fPersistentCache = &mSkSLCacheMonitor;
+ std::tie(mGrContext, mProtectedGrContext) = createDirectContexts(options);
+}
+
+void SkiaRenderEngine::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
+ bool isRenderable) {
+ // Only run this if RE is running on its own thread. This way the access to GL
+ // operations is guaranteed to be happening on the same thread.
+ if (mRenderEngineType != RenderEngineType::SKIA_GL_THREADED) {
+ return;
+ }
+ // We currently don't attempt to map a buffer if the buffer contains protected content
+ // because GPU resources for protected buffers is much more limited.
+ const bool isProtectedBuffer = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
+ if (isProtectedBuffer) {
+ return;
+ }
+ ATRACE_CALL();
+
+ // If we were to support caching protected buffers then we will need to switch the
+ // currently bound context if we are not already using the protected context (and subsequently
+ // switch back after the buffer is cached). However, for non-protected content we can bind
+ // the texture in either GL context because they are initialized with the same share_context
+ // which allows the texture state to be shared between them.
+ auto grContext = getActiveGrContext();
+ auto& cache = mTextureCache;
+
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ mGraphicBufferExternalRefs[buffer->getId()]++;
+
+ if (const auto& iter = cache.find(buffer->getId()); iter == cache.end()) {
+ std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef =
+ std::make_shared<AutoBackendTexture::LocalRef>(grContext,
+ buffer->toAHardwareBuffer(),
+ isRenderable, mTextureCleanupMgr);
+ cache.insert({buffer->getId(), imageTextureRef});
+ }
+}
+
+void SkiaRenderEngine::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ if (const auto& iter = mGraphicBufferExternalRefs.find(buffer->getId());
+ iter != mGraphicBufferExternalRefs.end()) {
+ if (iter->second == 0) {
+ ALOGW("Attempted to unmap GraphicBuffer <id: %" PRId64
+ "> from RenderEngine texture, but the "
+ "ref count was already zero!",
+ buffer->getId());
+ mGraphicBufferExternalRefs.erase(buffer->getId());
+ return;
+ }
+
+ iter->second--;
+
+ // Swap contexts if needed prior to deleting this buffer
+ // See Issue 1 of
+ // https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_protected_content.txt: even
+ // when a protected context and an unprotected context are part of the same share group,
+ // protected surfaces may not be accessed by an unprotected context, implying that protected
+ // surfaces may only be freed when a protected context is active.
+ const bool inProtected = mInProtectedContext;
+ useProtectedContext(buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+
+ if (iter->second == 0) {
+ mTextureCache.erase(buffer->getId());
+ mGraphicBufferExternalRefs.erase(buffer->getId());
+ }
+
+ // Swap back to the previous context so that cached values of isProtected in SurfaceFlinger
+ // are up-to-date.
+ if (inProtected != mInProtectedContext) {
+ useProtectedContext(inProtected);
+ }
+ }
+}
+
+bool SkiaRenderEngine::canSkipPostRenderCleanup() const {
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ return mTextureCleanupMgr.isEmpty();
+}
+
+void SkiaRenderEngine::cleanupPostRender() {
+ ATRACE_CALL();
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ mTextureCleanupMgr.cleanup();
+}
+
+sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader(
+ const RuntimeEffectShaderParameters& parameters) {
+ // The given surface will be stretched by HWUI via matrix transformation
+ // which gets similar results for most surfaces
+ // Determine later on if we need to leverage the stertch shader within
+ // surface flinger
+ const auto& stretchEffect = parameters.layer.stretchEffect;
+ auto shader = parameters.shader;
+ if (stretchEffect.hasEffect()) {
+ const auto targetBuffer = parameters.layer.source.buffer.buffer;
+ const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
+ if (graphicBuffer && parameters.shader) {
+ shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
+ }
+ }
+
+ if (parameters.requiresLinearEffect) {
+ const ui::Dataspace inputDataspace = mUseColorManagement ? parameters.layer.sourceDataspace
+ : ui::Dataspace::V0_SRGB_LINEAR;
+ const ui::Dataspace outputDataspace = mUseColorManagement
+ ? parameters.display.outputDataspace
+ : ui::Dataspace::V0_SRGB_LINEAR;
+
+ auto effect =
+ shaders::LinearEffect{.inputDataspace = inputDataspace,
+ .outputDataspace = outputDataspace,
+ .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha};
+
+ auto effectIter = mRuntimeEffects.find(effect);
+ sk_sp<SkRuntimeEffect> runtimeEffect = nullptr;
+ if (effectIter == mRuntimeEffects.end()) {
+ runtimeEffect = buildRuntimeEffect(effect);
+ mRuntimeEffects.insert({effect, runtimeEffect});
+ } else {
+ runtimeEffect = effectIter->second;
+ }
+ mat4 colorTransform = parameters.layer.colorTransform;
+
+ colorTransform *=
+ mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio,
+ parameters.layerDimmingRatio, 1.f));
+ const auto targetBuffer = parameters.layer.source.buffer.buffer;
+ const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
+ const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr;
+ return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform,
+ parameters.display.maxLuminance,
+ parameters.display.currentLuminanceNits,
+ parameters.layer.source.buffer.maxLuminanceNits,
+ hardwareBuffer, parameters.display.renderIntent);
+ }
+ return parameters.shader;
+}
+
+void SkiaRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) {
+ if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+ // Record display settings when capture is running.
+ std::stringstream displaySettings;
+ PrintTo(display, &displaySettings);
+ // Store the DisplaySettings in additional information.
+ canvas->drawAnnotation(SkRect::MakeEmpty(), "DisplaySettings",
+ SkData::MakeWithCString(displaySettings.str().c_str()));
+ }
+
+ // Before doing any drawing, let's make sure that we'll start at the origin of the display.
+ // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
+ // displays might have different scaling when compared to the physical screen.
+
+ canvas->clipRect(getSkRect(display.physicalDisplay));
+ canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
+
+ const auto clipWidth = display.clip.width();
+ const auto clipHeight = display.clip.height();
+ auto rotatedClipWidth = clipWidth;
+ auto rotatedClipHeight = clipHeight;
+ // Scale is contingent on the rotation result.
+ if (display.orientation & ui::Transform::ROT_90) {
+ std::swap(rotatedClipWidth, rotatedClipHeight);
+ }
+ const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
+ static_cast<SkScalar>(rotatedClipWidth);
+ const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
+ static_cast<SkScalar>(rotatedClipHeight);
+ canvas->scale(scaleX, scaleY);
+
+ // Canvas rotation is done by centering the clip window at the origin, rotating, translating
+ // back so that the top left corner of the clip is at (0, 0).
+ canvas->translate(rotatedClipWidth / 2, rotatedClipHeight / 2);
+ canvas->rotate(toDegrees(display.orientation));
+ canvas->translate(-clipWidth / 2, -clipHeight / 2);
+ canvas->translate(-display.clip.left, -display.clip.top);
+}
+
+class AutoSaveRestore {
+public:
+ AutoSaveRestore(SkCanvas* canvas) : mCanvas(canvas) { mSaveCount = canvas->save(); }
+ ~AutoSaveRestore() { restore(); }
+ void replace(SkCanvas* canvas) {
+ mCanvas = canvas;
+ mSaveCount = canvas->save();
+ }
+ void restore() {
+ if (mCanvas) {
+ mCanvas->restoreToCount(mSaveCount);
+ mCanvas = nullptr;
+ }
+ }
+
+private:
+ SkCanvas* mCanvas;
+ int mSaveCount;
+};
+
+static SkRRect getBlurRRect(const BlurRegion& region) {
+ const auto rect = SkRect::MakeLTRB(region.left, region.top, region.right, region.bottom);
+ const SkVector radii[4] = {SkVector::Make(region.cornerRadiusTL, region.cornerRadiusTL),
+ SkVector::Make(region.cornerRadiusTR, region.cornerRadiusTR),
+ SkVector::Make(region.cornerRadiusBR, region.cornerRadiusBR),
+ SkVector::Make(region.cornerRadiusBL, region.cornerRadiusBL)};
+ SkRRect roundedRect;
+ roundedRect.setRectRadii(rect, radii);
+ return roundedRect;
+}
+
+// Arbitrary default margin which should be close enough to zero.
+constexpr float kDefaultMargin = 0.0001f;
+static bool equalsWithinMargin(float expected, float value, float margin = kDefaultMargin) {
+ LOG_ALWAYS_FATAL_IF(margin < 0.f, "Margin is negative!");
+ return std::abs(expected - value) < margin;
+}
+
+namespace {
+template <typename T>
+void logSettings(const T& t) {
+ std::stringstream stream;
+ PrintTo(t, &stream);
+ auto string = stream.str();
+ size_t pos = 0;
+ // Perfetto ignores \n, so split up manually into separate ALOGD statements.
+ const size_t size = string.size();
+ while (pos < size) {
+ const size_t end = std::min(string.find("\n", pos), size);
+ ALOGD("%s", string.substr(pos, end - pos).c_str());
+ pos = end + 1;
+ }
+}
+} // namespace
+
+// Helper class intended to be used on the stack to ensure that texture cleanup
+// is deferred until after this class goes out of scope.
+class DeferTextureCleanup final {
+public:
+ DeferTextureCleanup(AutoBackendTexture::CleanupManager& mgr) : mMgr(mgr) {
+ mMgr.setDeferredStatus(true);
+ }
+ ~DeferTextureCleanup() { mMgr.setDeferredStatus(false); }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(DeferTextureCleanup);
+ AutoBackendTexture::CleanupManager& mMgr;
+};
+
+void SkiaRenderEngine::drawLayersInternal(
+ const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display, const std::vector<LayerSettings>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/,
+ base::unique_fd&& bufferFence) {
+ ATRACE_NAME("SkiaGL::drawLayersInternal");
+
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+
+ if (buffer == nullptr) {
+ ALOGE("No output buffer provided. Aborting GPU composition.");
+ resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+ return;
+ }
+
+ validateOutputBufferUsage(buffer->getBuffer());
+
+ auto grContext = getActiveGrContext();
+ auto& cache = mTextureCache;
+
+ // any AutoBackendTexture deletions will now be deferred until cleanupPostRender is called
+ DeferTextureCleanup dtc(mTextureCleanupMgr);
+
+ std::shared_ptr<AutoBackendTexture::LocalRef> surfaceTextureRef;
+ if (const auto& it = cache.find(buffer->getBuffer()->getId()); it != cache.end()) {
+ surfaceTextureRef = it->second;
+ } else {
+ surfaceTextureRef =
+ std::make_shared<AutoBackendTexture::LocalRef>(grContext,
+ buffer->getBuffer()
+ ->toAHardwareBuffer(),
+ true, mTextureCleanupMgr);
+ }
+
+ // wait on the buffer to be ready to use prior to using it
+ waitFence(grContext, bufferFence);
+
+ const ui::Dataspace dstDataspace =
+ mUseColorManagement ? display.outputDataspace : ui::Dataspace::V0_SRGB_LINEAR;
+ sk_sp<SkSurface> dstSurface = surfaceTextureRef->getOrCreateSurface(dstDataspace, grContext);
+
+ SkCanvas* dstCanvas = mCapture->tryCapture(dstSurface.get());
+ if (dstCanvas == nullptr) {
+ ALOGE("Cannot acquire canvas from Skia.");
+ resultPromise->set_value({BAD_VALUE, base::unique_fd()});
+ return;
+ }
+
+ // setup color filter if necessary
+ sk_sp<SkColorFilter> displayColorTransform;
+ if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
+ displayColorTransform = SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform));
+ }
+ const bool ctModifiesAlpha =
+ displayColorTransform && !displayColorTransform->isAlphaUnchanged();
+
+ // Find the max layer white point to determine the max luminance of the scene...
+ const float maxLayerWhitePoint = std::transform_reduce(
+ layers.cbegin(), layers.cend(), 0.f,
+ [](float left, float right) { return std::max(left, right); },
+ [&](const auto& l) { return l.whitePointNits; });
+
+ // ...and compute the dimming ratio if dimming is requested
+ const float displayDimmingRatio = display.targetLuminanceNits > 0.f &&
+ maxLayerWhitePoint > 0.f && display.targetLuminanceNits > maxLayerWhitePoint
+ ? maxLayerWhitePoint / display.targetLuminanceNits
+ : 1.f;
+
+ // Find if any layers have requested blur, we'll use that info to decide when to render to an
+ // offscreen buffer and when to render to the native buffer.
+ sk_sp<SkSurface> activeSurface(dstSurface);
+ SkCanvas* canvas = dstCanvas;
+ SkiaCapture::OffscreenState offscreenCaptureState;
+ const LayerSettings* blurCompositionLayer = nullptr;
+ if (mBlurFilter) {
+ bool requiresCompositionLayer = false;
+ for (const auto& layer : layers) {
+ // if the layer doesn't have blur or it is not visible then continue
+ if (!layerHasBlur(layer, ctModifiesAlpha)) {
+ continue;
+ }
+ if (layer.backgroundBlurRadius > 0 &&
+ layer.backgroundBlurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
+ requiresCompositionLayer = true;
+ }
+ for (auto region : layer.blurRegions) {
+ if (region.blurRadius < mBlurFilter->getMaxCrossFadeRadius()) {
+ requiresCompositionLayer = true;
+ }
+ }
+ if (requiresCompositionLayer) {
+ activeSurface = dstSurface->makeSurface(dstSurface->imageInfo());
+ canvas = mCapture->tryOffscreenCapture(activeSurface.get(), &offscreenCaptureState);
+ blurCompositionLayer = &layer;
+ break;
+ }
+ }
+ }
+
+ AutoSaveRestore surfaceAutoSaveRestore(canvas);
+ // Clear the entire canvas with a transparent black to prevent ghost images.
+ canvas->clear(SK_ColorTRANSPARENT);
+ initCanvas(canvas, display);
+
+ if (kPrintLayerSettings) {
+ logSettings(display);
+ }
+ for (const auto& layer : layers) {
+ ATRACE_FORMAT("DrawLayer: %s", layer.name.c_str());
+
+ if (kPrintLayerSettings) {
+ logSettings(layer);
+ }
+
+ sk_sp<SkImage> blurInput;
+ if (blurCompositionLayer == &layer) {
+ LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface);
+ LOG_ALWAYS_FATAL_IF(canvas == dstCanvas);
+
+ // save a snapshot of the activeSurface to use as input to the blur shaders
+ blurInput = activeSurface->makeImageSnapshot();
+
+ // blit the offscreen framebuffer into the destination AHB, but only
+ // if there are blur regions. backgroundBlurRadius blurs the entire
+ // image below, so it can skip this step.
+ if (layer.blurRegions.size()) {
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kSrc);
+ if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+ uint64_t id = mCapture->endOffscreenCapture(&offscreenCaptureState);
+ dstCanvas->drawAnnotation(SkRect::Make(dstCanvas->imageInfo().dimensions()),
+ String8::format("SurfaceID|%" PRId64, id).c_str(),
+ nullptr);
+ dstCanvas->drawImage(blurInput, 0, 0, SkSamplingOptions(), &paint);
+ } else {
+ activeSurface->draw(dstCanvas, 0, 0, SkSamplingOptions(), &paint);
+ }
+ }
+
+ // assign dstCanvas to canvas and ensure that the canvas state is up to date
+ canvas = dstCanvas;
+ surfaceAutoSaveRestore.replace(canvas);
+ initCanvas(canvas, display);
+
+ LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getSaveCount() !=
+ dstSurface->getCanvas()->getSaveCount());
+ LOG_ALWAYS_FATAL_IF(activeSurface->getCanvas()->getTotalMatrix() !=
+ dstSurface->getCanvas()->getTotalMatrix());
+
+ // assign dstSurface to activeSurface
+ activeSurface = dstSurface;
+ }
+
+ SkAutoCanvasRestore layerAutoSaveRestore(canvas, true);
+ if (CC_UNLIKELY(mCapture->isCaptureRunning())) {
+ // Record the name of the layer if the capture is running.
+ std::stringstream layerSettings;
+ PrintTo(layer, &layerSettings);
+ // Store the LayerSettings in additional information.
+ canvas->drawAnnotation(SkRect::MakeEmpty(), layer.name.c_str(),
+ SkData::MakeWithCString(layerSettings.str().c_str()));
+ }
+ // Layers have a local transform that should be applied to them
+ canvas->concat(getSkM44(layer.geometry.positionTransform).asM33());
+
+ const auto [bounds, roundRectClip] =
+ getBoundsAndClip(layer.geometry.boundaries, layer.geometry.roundedCornersCrop,
+ layer.geometry.roundedCornersRadius);
+ if (mBlurFilter && layerHasBlur(layer, ctModifiesAlpha)) {
+ std::unordered_map<uint32_t, sk_sp<SkImage>> cachedBlurs;
+
+ // if multiple layers have blur, then we need to take a snapshot now because
+ // only the lowest layer will have blurImage populated earlier
+ if (!blurInput) {
+ blurInput = activeSurface->makeImageSnapshot();
+ }
+ // rect to be blurred in the coordinate space of blurInput
+ const auto blurRect = canvas->getTotalMatrix().mapRect(bounds.rect());
+
+ // if the clip needs to be applied then apply it now and make sure
+ // it is restored before we attempt to draw any shadows.
+ SkAutoCanvasRestore acr(canvas, true);
+ if (!roundRectClip.isEmpty()) {
+ canvas->clipRRect(roundRectClip, true);
+ }
+
+ // TODO(b/182216890): Filter out empty layers earlier
+ if (blurRect.width() > 0 && blurRect.height() > 0) {
+ if (layer.backgroundBlurRadius > 0) {
+ ATRACE_NAME("BackgroundBlur");
+ auto blurredImage = mBlurFilter->generate(grContext, layer.backgroundBlurRadius,
+ blurInput, blurRect);
+
+ cachedBlurs[layer.backgroundBlurRadius] = blurredImage;
+
+ mBlurFilter->drawBlurRegion(canvas, bounds, layer.backgroundBlurRadius, 1.0f,
+ blurRect, blurredImage, blurInput);
+ }
+
+ canvas->concat(getSkM44(layer.blurRegionTransform).asM33());
+ for (auto region : layer.blurRegions) {
+ if (cachedBlurs[region.blurRadius] == nullptr) {
+ ATRACE_NAME("BlurRegion");
+ cachedBlurs[region.blurRadius] =
+ mBlurFilter->generate(grContext, region.blurRadius, blurInput,
+ blurRect);
+ }
+
+ mBlurFilter->drawBlurRegion(canvas, getBlurRRect(region), region.blurRadius,
+ region.alpha, blurRect,
+ cachedBlurs[region.blurRadius], blurInput);
+ }
+ }
+ }
+
+ if (layer.shadow.length > 0) {
+ // This would require a new parameter/flag to SkShadowUtils::DrawShadow
+ LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with a shadow");
+
+ SkRRect shadowBounds, shadowClip;
+ if (layer.geometry.boundaries == layer.shadow.boundaries) {
+ shadowBounds = bounds;
+ shadowClip = roundRectClip;
+ } else {
+ std::tie(shadowBounds, shadowClip) =
+ getBoundsAndClip(layer.shadow.boundaries, layer.geometry.roundedCornersCrop,
+ layer.geometry.roundedCornersRadius);
+ }
+
+ // Technically, if bounds is a rect and roundRectClip is not empty,
+ // it means that the bounds and roundedCornersCrop were different
+ // enough that we should intersect them to find the proper shadow.
+ // In practice, this often happens when the two rectangles appear to
+ // not match due to rounding errors. Draw the rounded version, which
+ // looks more like the intent.
+ const auto& rrect =
+ shadowBounds.isRect() && !shadowClip.isEmpty() ? shadowClip : shadowBounds;
+ drawShadow(canvas, rrect, layer.shadow);
+ }
+
+ const float layerDimmingRatio = layer.whitePointNits <= 0.f
+ ? displayDimmingRatio
+ : (layer.whitePointNits / maxLayerWhitePoint) * displayDimmingRatio;
+
+ const bool dimInLinearSpace = display.dimmingStage !=
+ aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF;
+
+ const bool requiresLinearEffect = layer.colorTransform != mat4() ||
+ (mUseColorManagement &&
+ needsToneMapping(layer.sourceDataspace, display.outputDataspace)) ||
+ (dimInLinearSpace && !equalsWithinMargin(1.f, layerDimmingRatio));
+
+ // quick abort from drawing the remaining portion of the layer
+ if (layer.skipContentDraw ||
+ (layer.alpha == 0 && !requiresLinearEffect && !layer.disableBlending &&
+ (!displayColorTransform || displayColorTransform->isAlphaUnchanged()))) {
+ continue;
+ }
+
+ // If we need to map to linear space or color management is disabled, then mark the source
+ // image with the same colorspace as the destination surface so that Skia's color
+ // management is a no-op.
+ const ui::Dataspace layerDataspace = (!mUseColorManagement || requiresLinearEffect)
+ ? dstDataspace
+ : layer.sourceDataspace;
+
+ SkPaint paint;
+ if (layer.source.buffer.buffer) {
+ ATRACE_NAME("DrawImage");
+ validateInputBufferUsage(layer.source.buffer.buffer->getBuffer());
+ const auto& item = layer.source.buffer;
+ std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr;
+
+ if (const auto& iter = cache.find(item.buffer->getBuffer()->getId());
+ iter != cache.end()) {
+ imageTextureRef = iter->second;
+ } else {
+ // If we didn't find the image in the cache, then create a local ref but don't cache
+ // it. If we're using skia, we're guaranteed to run on a dedicated GPU thread so if
+ // we didn't find anything in the cache then we intentionally did not cache this
+ // buffer's resources.
+ imageTextureRef = std::make_shared<
+ AutoBackendTexture::LocalRef>(grContext,
+ item.buffer->getBuffer()->toAHardwareBuffer(),
+ false, mTextureCleanupMgr);
+ }
+
+ // if the layer's buffer has a fence, then we must must respect the fence prior to using
+ // the buffer.
+ if (layer.source.buffer.fence != nullptr) {
+ waitFence(grContext, layer.source.buffer.fence->get());
+ }
+
+ // isOpaque means we need to ignore the alpha in the image,
+ // replacing it with the alpha specified by the LayerSettings. See
+ // https://developer.android.com/reference/android/view/SurfaceControl.Builder#setOpaque(boolean)
+ // The proper way to do this is to use an SkColorType that ignores
+ // alpha, like kRGB_888x_SkColorType, and that is used if the
+ // incoming image is kRGBA_8888_SkColorType. However, the incoming
+ // image may be kRGBA_F16_SkColorType, for which there is no RGBX
+ // SkColorType, or kRGBA_1010102_SkColorType, for which we have
+ // kRGB_101010x_SkColorType, but it is not yet supported as a source
+ // on the GPU. (Adding both is tracked in skbug.com/12048.) In the
+ // meantime, we'll use a workaround that works unless we need to do
+ // any color conversion. The workaround requires that we pretend the
+ // image is already premultiplied, so that we do not premultiply it
+ // before applying SkBlendMode::kPlus.
+ const bool useIsOpaqueWorkaround = item.isOpaque &&
+ (imageTextureRef->colorType() == kRGBA_1010102_SkColorType ||
+ imageTextureRef->colorType() == kRGBA_F16_SkColorType);
+ const auto alphaType = useIsOpaqueWorkaround ? kPremul_SkAlphaType
+ : item.isOpaque ? kOpaque_SkAlphaType
+ : item.usePremultipliedAlpha ? kPremul_SkAlphaType
+ : kUnpremul_SkAlphaType;
+ sk_sp<SkImage> image = imageTextureRef->makeImage(layerDataspace, alphaType, grContext);
+
+ auto texMatrix = getSkM44(item.textureTransform).asM33();
+ // textureTansform was intended to be passed directly into a shader, so when
+ // building the total matrix with the textureTransform we need to first
+ // normalize it, then apply the textureTransform, then scale back up.
+ texMatrix.preScale(1.0f / bounds.width(), 1.0f / bounds.height());
+ texMatrix.postScale(image->width(), image->height());
+
+ SkMatrix matrix;
+ if (!texMatrix.invert(&matrix)) {
+ matrix = texMatrix;
+ }
+ // The shader does not respect the translation, so we add it to the texture
+ // transform for the SkImage. This will make sure that the correct layer contents
+ // are drawn in the correct part of the screen.
+ matrix.postTranslate(bounds.rect().fLeft, bounds.rect().fTop);
+
+ sk_sp<SkShader> shader;
+
+ if (layer.source.buffer.useTextureFiltering) {
+ shader = image->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
+ SkSamplingOptions(
+ {SkFilterMode::kLinear, SkMipmapMode::kNone}),
+ &matrix);
+ } else {
+ shader = image->makeShader(SkSamplingOptions(), matrix);
+ }
+
+ if (useIsOpaqueWorkaround) {
+ shader = SkShaders::Blend(SkBlendMode::kPlus, shader,
+ SkShaders::Color(SkColors::kBlack,
+ toSkColorSpace(layerDataspace)));
+ }
+
+ paint.setShader(createRuntimeEffectShader(
+ RuntimeEffectShaderParameters{.shader = shader,
+ .layer = layer,
+ .display = display,
+ .undoPremultipliedAlpha = !item.isOpaque &&
+ item.usePremultipliedAlpha,
+ .requiresLinearEffect = requiresLinearEffect,
+ .layerDimmingRatio = dimInLinearSpace
+ ? layerDimmingRatio
+ : 1.f}));
+
+ // Turn on dithering when dimming beyond this (arbitrary) threshold...
+ static constexpr float kDimmingThreshold = 0.2f;
+ // ...or we're rendering an HDR layer down to an 8-bit target
+ // Most HDR standards require at least 10-bits of color depth for source content, so we
+ // can just extract the transfer function rather than dig into precise gralloc layout.
+ // Furthermore, we can assume that the only 8-bit target we support is RGBA8888.
+ const bool requiresDownsample = isHdrDataspace(layer.sourceDataspace) &&
+ buffer->getPixelFormat() == PIXEL_FORMAT_RGBA_8888;
+ if (layerDimmingRatio <= kDimmingThreshold || requiresDownsample) {
+ paint.setDither(true);
+ }
+ paint.setAlphaf(layer.alpha);
+
+ if (imageTextureRef->colorType() == kAlpha_8_SkColorType) {
+ LOG_ALWAYS_FATAL_IF(layer.disableBlending, "Cannot disableBlending with A8");
+
+ // SysUI creates the alpha layer as a coverage layer, which is
+ // appropriate for the DPU. Use a color matrix to convert it to
+ // a mask.
+ // TODO (b/219525258): Handle input as a mask.
+ //
+ // The color matrix will convert A8 pixels with no alpha to
+ // black, as described by this vector. If the display handles
+ // the color transform, we need to invert it to find the color
+ // that will result in black after the DPU applies the transform.
+ SkV4 black{0.0f, 0.0f, 0.0f, 1.0f}; // r, g, b, a
+ if (display.colorTransform != mat4() && display.deviceHandlesColorTransform) {
+ SkM44 colorSpaceMatrix = getSkM44(display.colorTransform);
+ if (colorSpaceMatrix.invert(&colorSpaceMatrix)) {
+ black = colorSpaceMatrix * black;
+ } else {
+ // We'll just have to use 0,0,0 as black, which should
+ // be close to correct.
+ ALOGI("Could not invert colorTransform!");
+ }
+ }
+ SkColorMatrix colorMatrix(0, 0, 0, 0, black[0],
+ 0, 0, 0, 0, black[1],
+ 0, 0, 0, 0, black[2],
+ 0, 0, 0, -1, 1);
+ if (display.colorTransform != mat4() && !display.deviceHandlesColorTransform) {
+ // On the other hand, if the device doesn't handle it, we
+ // have to apply it ourselves.
+ colorMatrix.postConcat(toSkColorMatrix(display.colorTransform));
+ }
+ paint.setColorFilter(SkColorFilters::Matrix(colorMatrix));
+ }
+ } else {
+ ATRACE_NAME("DrawColor");
+ const auto color = layer.source.solidColor;
+ sk_sp<SkShader> shader = SkShaders::Color(SkColor4f{.fR = color.r,
+ .fG = color.g,
+ .fB = color.b,
+ .fA = layer.alpha},
+ toSkColorSpace(layerDataspace));
+ paint.setShader(createRuntimeEffectShader(
+ RuntimeEffectShaderParameters{.shader = shader,
+ .layer = layer,
+ .display = display,
+ .undoPremultipliedAlpha = false,
+ .requiresLinearEffect = requiresLinearEffect,
+ .layerDimmingRatio = layerDimmingRatio}));
+ }
+
+ if (layer.disableBlending) {
+ paint.setBlendMode(SkBlendMode::kSrc);
+ }
+
+ // An A8 buffer will already have the proper color filter attached to
+ // its paint, including the displayColorTransform as needed.
+ if (!paint.getColorFilter()) {
+ if (!dimInLinearSpace && !equalsWithinMargin(1.0, layerDimmingRatio)) {
+ // If we don't dim in linear space, then when we gamma correct the dimming ratio we
+ // can assume a gamma 2.2 transfer function.
+ static constexpr float kInverseGamma22 = 1.f / 2.2f;
+ const auto gammaCorrectedDimmingRatio =
+ std::pow(layerDimmingRatio, kInverseGamma22);
+ auto dimmingMatrix =
+ mat4::scale(vec4(gammaCorrectedDimmingRatio, gammaCorrectedDimmingRatio,
+ gammaCorrectedDimmingRatio, 1.f));
+
+ const auto colorFilter =
+ SkColorFilters::Matrix(toSkColorMatrix(std::move(dimmingMatrix)));
+ paint.setColorFilter(displayColorTransform
+ ? displayColorTransform->makeComposed(colorFilter)
+ : colorFilter);
+ } else {
+ paint.setColorFilter(displayColorTransform);
+ }
+ }
+
+ if (!roundRectClip.isEmpty()) {
+ canvas->clipRRect(roundRectClip, true);
+ }
+
+ if (!bounds.isRect()) {
+ paint.setAntiAlias(true);
+ canvas->drawRRect(bounds, paint);
+ } else {
+ canvas->drawRect(bounds.rect(), paint);
+ }
+ if (kFlushAfterEveryLayer) {
+ ATRACE_NAME("flush surface");
+ activeSurface->flush();
+ }
+ }
+ for (const auto& borderRenderInfo : display.borderInfoList) {
+ SkPaint p;
+ p.setColor(SkColor4f{borderRenderInfo.color.r, borderRenderInfo.color.g,
+ borderRenderInfo.color.b, borderRenderInfo.color.a});
+ p.setAntiAlias(true);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setStrokeWidth(borderRenderInfo.width);
+ SkRegion sk_region;
+ SkPath path;
+
+ // Construct a final SkRegion using Regions
+ for (const auto& r : borderRenderInfo.combinedRegion) {
+ sk_region.op({r.left, r.top, r.right, r.bottom}, SkRegion::kUnion_Op);
+ }
+
+ sk_region.getBoundaryPath(&path);
+ canvas->drawPath(path, p);
+ path.close();
+ }
+
+ surfaceAutoSaveRestore.restore();
+ mCapture->endCapture();
+ {
+ ATRACE_NAME("flush surface");
+ LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface);
+ activeSurface->flush();
+ }
+
+ base::unique_fd drawFence = flushAndSubmit(grContext);
+ resultPromise->set_value({NO_ERROR, std::move(drawFence)});
+ return;
+}
+
+size_t SkiaRenderEngine::getMaxTextureSize() const {
+ return mGrContext->maxTextureSize();
+}
+
+size_t SkiaRenderEngine::getMaxViewportDims() const {
+ return mGrContext->maxRenderTargetSize();
+}
+
+void SkiaRenderEngine::drawShadow(SkCanvas* canvas,
+ const SkRRect& casterRRect,
+ const ShadowSettings& settings) {
+ ATRACE_CALL();
+ const float casterZ = settings.length / 2.0f;
+ const auto flags =
+ settings.casterIsTranslucent ? kTransparentOccluder_ShadowFlag : kNone_ShadowFlag;
+
+ SkShadowUtils::DrawShadow(canvas, SkPath::RRect(casterRRect), SkPoint3::Make(0, 0, casterZ),
+ getSkPoint3(settings.lightPos), settings.lightRadius,
+ getSkColor(settings.ambientColor), getSkColor(settings.spotColor),
+ flags);
+}
+
+void SkiaRenderEngine::onActiveDisplaySizeChanged(ui::Size size) {
+ // This cache multiplier was selected based on review of cache sizes relative
+ // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x),
+ // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a
+ // conservative default based on that analysis.
+ const float SURFACE_SIZE_MULTIPLIER = 3.5f * bytesPerPixel(mDefaultPixelFormat);
+ const int maxResourceBytes = size.width * size.height * SURFACE_SIZE_MULTIPLIER;
+
+ // start by resizing the current context
+ getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
+
+ // if it is possible to switch contexts then we will resize the other context
+ const bool originalProtectedState = mInProtectedContext;
+ useProtectedContext(!mInProtectedContext);
+ if (mInProtectedContext != originalProtectedState) {
+ getActiveGrContext()->setResourceCacheLimit(maxResourceBytes);
+ // reset back to the initial context that was active when this method was called
+ useProtectedContext(originalProtectedState);
+ }
+}
+
+void SkiaRenderEngine::dump(std::string& result) {
+ // Dump for the specific backend (GLES or Vk)
+ appendBackendSpecificInfoToDump(result);
+
+ // Info about protected content
+ StringAppendF(&result, "RenderEngine supports protected context: %d\n",
+ supportsProtectedContent());
+ StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext);
+ StringAppendF(&result, "RenderEngine shaders cached since last dump/primeCache: %d\n",
+ mSkSLCacheMonitor.shadersCachedSinceLastCall());
+
+ std::vector<ResourcePair> cpuResourceMap = {
+ {"skia/sk_resource_cache/bitmap_", "Bitmaps"},
+ {"skia/sk_resource_cache/rrect-blur_", "Masks"},
+ {"skia/sk_resource_cache/rects-blur_", "Masks"},
+ {"skia/sk_resource_cache/tessellated", "Shadows"},
+ {"skia", "Other"},
+ };
+ SkiaMemoryReporter cpuReporter(cpuResourceMap, false);
+ SkGraphics::DumpMemoryStatistics(&cpuReporter);
+ StringAppendF(&result, "Skia CPU Caches: ");
+ cpuReporter.logTotals(result);
+ cpuReporter.logOutput(result);
+
+ {
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+
+ std::vector<ResourcePair> gpuResourceMap = {
+ {"texture_renderbuffer", "Texture/RenderBuffer"},
+ {"texture", "Texture"},
+ {"gr_text_blob_cache", "Text"},
+ {"skia", "Other"},
+ };
+ SkiaMemoryReporter gpuReporter(gpuResourceMap, true);
+ mGrContext->dumpMemoryStatistics(&gpuReporter);
+ StringAppendF(&result, "Skia's GPU Caches: ");
+ gpuReporter.logTotals(result);
+ gpuReporter.logOutput(result);
+ StringAppendF(&result, "Skia's Wrapped Objects:\n");
+ gpuReporter.logOutput(result, true);
+
+ StringAppendF(&result, "RenderEngine tracked buffers: %zu\n",
+ mGraphicBufferExternalRefs.size());
+ StringAppendF(&result, "Dumping buffer ids...\n");
+ for (const auto& [id, refCounts] : mGraphicBufferExternalRefs) {
+ StringAppendF(&result, "- 0x%" PRIx64 " - %d refs \n", id, refCounts);
+ }
+ StringAppendF(&result, "RenderEngine AHB/BackendTexture cache size: %zu\n",
+ mTextureCache.size());
+ StringAppendF(&result, "Dumping buffer ids...\n");
+ // TODO(178539829): It would be nice to know which layer these are coming from and what
+ // the texture sizes are.
+ for (const auto& [id, unused] : mTextureCache) {
+ StringAppendF(&result, "- 0x%" PRIx64 "\n", id);
+ }
+ StringAppendF(&result, "\n");
+
+ SkiaMemoryReporter gpuProtectedReporter(gpuResourceMap, true);
+ if (mProtectedGrContext) {
+ mProtectedGrContext->dumpMemoryStatistics(&gpuProtectedReporter);
+ }
+ StringAppendF(&result, "Skia's GPU Protected Caches: ");
+ gpuProtectedReporter.logTotals(result);
+ gpuProtectedReporter.logOutput(result);
+ StringAppendF(&result, "Skia's Protected Wrapped Objects:\n");
+ gpuProtectedReporter.logOutput(result, true);
+
+ StringAppendF(&result, "\n");
+ StringAppendF(&result, "RenderEngine runtime effects: %zu\n", mRuntimeEffects.size());
+ for (const auto& [linearEffect, unused] : mRuntimeEffects) {
+ StringAppendF(&result, "- inputDataspace: %s\n",
+ dataspaceDetails(
+ static_cast<android_dataspace>(linearEffect.inputDataspace))
+ .c_str());
+ StringAppendF(&result, "- outputDataspace: %s\n",
+ dataspaceDetails(
+ static_cast<android_dataspace>(linearEffect.outputDataspace))
+ .c_str());
+ StringAppendF(&result, "undoPremultipliedAlpha: %s\n",
+ linearEffect.undoPremultipliedAlpha ? "true" : "false");
+ }
+ }
+ StringAppendF(&result, "\n");
+}
+
} // namespace skia
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h
index 160a186..a5cd278 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.h
+++ b/libs/renderengine/skia/SkiaRenderEngine.h
@@ -20,6 +20,31 @@
#include <renderengine/RenderEngine.h>
#include <sys/types.h>
+#include <GrBackendSemaphore.h>
+#include <GrDirectContext.h>
+#include <SkSurface.h>
+#include <android-base/thread_annotations.h>
+#include <renderengine/ExternalTexture.h>
+#include <renderengine/RenderEngine.h>
+#include <sys/types.h>
+
+#include <mutex>
+#include <unordered_map>
+
+#include "AutoBackendTexture.h"
+#include "GrContextOptions.h"
+#include "SkImageInfo.h"
+#include "SkiaRenderEngine.h"
+#include "android-base/macros.h"
+#include "debug/SkiaCapture.h"
+#include "filters/BlurFilter.h"
+#include "filters/LinearEffect.h"
+#include "filters/StretchShaderFactory.h"
+
+class SkData;
+
+struct SkPoint3;
+
namespace android {
namespace renderengine {
@@ -31,35 +56,141 @@
class BlurFilter;
-// TODO: Put common skia stuff here that can be shared between the GL & Vulkan backends
-// Currently mostly just handles all the no-op / missing APIs
class SkiaRenderEngine : public RenderEngine {
public:
static std::unique_ptr<SkiaRenderEngine> create(const RenderEngineCreationArgs& args);
- SkiaRenderEngine(RenderEngineType type);
- ~SkiaRenderEngine() override {}
+ SkiaRenderEngine(RenderEngineType type,
+ PixelFormat pixelFormat,
+ bool useColorManagement,
+ bool supportsBackgroundBlur);
+ ~SkiaRenderEngine() override;
- virtual std::future<void> primeCache() override { return {}; };
- virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override{};
- virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override{};
- virtual bool isProtected() const override { return false; } // mInProtectedContext; }
- virtual bool supportsProtectedContent() const override { return false; };
- virtual int getContextPriority() override { return 0; }
- virtual int reportShadersCompiled() { return 0; }
- virtual void setEnableTracing(bool tracingEnabled) override;
+ std::future<void> primeCache() override final;
+ void cleanupPostRender() override final;
+ void cleanFramebufferCache() override final{ }
+ bool isProtected() const override final{ return mInProtectedContext; }
+ bool supportsBackgroundBlur() override final {
+ return mBlurFilter != nullptr;
+ }
+ void onActiveDisplaySizeChanged(ui::Size size) override final;
+ int reportShadersCompiled();
+ virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override final{};
+ virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override final{};
+ virtual void setEnableTracing(bool tracingEnabled) override final;
+
+ void useProtectedContext(bool useProtectedContext) override;
+ bool supportsProtectedContent() const override {
+ return supportsProtectedContentImpl();
+ }
+ void ensureGrContextsCreated();
protected:
- virtual void mapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/,
- bool /*isRenderable*/) override = 0;
- virtual void unmapExternalTextureBuffer(const sp<GraphicBuffer>& /*buffer*/) override = 0;
+ // This is so backends can stop the generic rendering state first before
+ // cleaning up backend-specific state
+ void finishRenderingAndAbandonContext();
- virtual void drawLayersInternal(
- const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
- const DisplaySettings& display, const std::vector<LayerSettings>& layers,
- const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
- base::unique_fd&& bufferFence) override {
- resultPromise->set_value({NO_ERROR, base::unique_fd()});
+ // Functions that a given backend (GLES, Vulkan) must implement
+ using Contexts = std::pair<sk_sp<GrDirectContext>, sk_sp<GrDirectContext>>;
+ virtual Contexts createDirectContexts(const GrContextOptions& options) = 0;
+ virtual bool supportsProtectedContentImpl() const = 0;
+ virtual bool useProtectedContextImpl(GrProtected isProtected) = 0;
+ virtual void waitFence(GrDirectContext* grContext, base::borrowed_fd fenceFd) = 0;
+ virtual base::unique_fd flushAndSubmit(GrDirectContext* context) = 0;
+ virtual void appendBackendSpecificInfoToDump(std::string& result) = 0;
+
+ size_t getMaxTextureSize() const override final;
+ size_t getMaxViewportDims() const override final;
+ GrDirectContext* getActiveGrContext();
+
+ // Implements PersistentCache as a way to monitor what SkSL shaders Skia has
+ // cached.
+ class SkSLCacheMonitor : public GrContextOptions::PersistentCache {
+ public:
+ SkSLCacheMonitor() = default;
+ ~SkSLCacheMonitor() override = default;
+
+ sk_sp<SkData> load(const SkData& key) override;
+
+ void store(const SkData& key, const SkData& data, const SkString& description) override;
+
+ int shadersCachedSinceLastCall() {
+ const int shadersCachedSinceLastCall = mShadersCachedSinceLastCall;
+ mShadersCachedSinceLastCall = 0;
+ return shadersCachedSinceLastCall;
+ }
+
+ int totalShadersCompiled() const { return mTotalShadersCompiled; }
+
+ private:
+ int mShadersCachedSinceLastCall = 0;
+ int mTotalShadersCompiled = 0;
};
+
+private:
+ void mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
+ bool isRenderable) override final;
+ void unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) override final;
+ bool canSkipPostRenderCleanup() const override final;
+
+ void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
+ void drawShadow(SkCanvas* canvas, const SkRRect& casterRRect,
+ const ShadowSettings& shadowSettings);
+ void drawLayersInternal(const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
+ const DisplaySettings& display,
+ const std::vector<LayerSettings>& layers,
+ const std::shared_ptr<ExternalTexture>& buffer,
+ const bool useFramebufferCache,
+ base::unique_fd&& bufferFence) override final;
+
+ void dump(std::string& result) override final;
+
+ // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned.
+ // Otherwise it returns the input shader.
+ struct RuntimeEffectShaderParameters {
+ sk_sp<SkShader> shader;
+ const LayerSettings& layer;
+ const DisplaySettings& display;
+ bool undoPremultipliedAlpha;
+ bool requiresLinearEffect;
+ float layerDimmingRatio;
+ };
+ sk_sp<SkShader> createRuntimeEffectShader(const RuntimeEffectShaderParameters&);
+
+ const PixelFormat mDefaultPixelFormat;
+ const bool mUseColorManagement;
+
+ // Identifier used for various mappings of layers to various
+ // textures or shaders
+ using GraphicBufferId = uint64_t;
+
+ // Number of external holders of ExternalTexture references, per GraphicBuffer ID.
+ std::unordered_map<GraphicBufferId, int32_t> mGraphicBufferExternalRefs
+ GUARDED_BY(mRenderingMutex);
+ // Cache of GL textures that we'll store per GraphicBuffer ID, shared between GPU contexts.
+ std::unordered_map<GraphicBufferId, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache
+ GUARDED_BY(mRenderingMutex);
+ std::unordered_map<shaders::LinearEffect, sk_sp<SkRuntimeEffect>, shaders::LinearEffectHasher>
+ mRuntimeEffects;
+ AutoBackendTexture::CleanupManager mTextureCleanupMgr GUARDED_BY(mRenderingMutex);
+
+ StretchShaderFactory mStretchShaderFactory;
+
+ sp<Fence> mLastDrawFence;
+ BlurFilter* mBlurFilter = nullptr;
+
+ // Object to capture commands send to Skia.
+ std::unique_ptr<SkiaCapture> mCapture;
+
+ // Mutex guarding rendering operations, so that internal state related to
+ // rendering that is potentially modified by multiple threads is guaranteed thread-safe.
+ mutable std::mutex mRenderingMutex;
+ SkSLCacheMonitor mSkSLCacheMonitor;
+
+ // Graphics context used for creating surfaces and submitting commands
+ sk_sp<GrDirectContext> mGrContext;
+ // Same as above, but for protected content (eg. DRM)
+ sk_sp<GrDirectContext> mProtectedGrContext;
+ bool mInProtectedContext = false;
};
} // namespace skia
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index f289730..d23063c 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -232,14 +232,14 @@
std::shared_ptr<renderengine::ExternalTexture> allocateDefaultBuffer() {
return std::make_shared<
renderengine::impl::
- ExternalTexture>(new GraphicBuffer(DEFAULT_DISPLAY_WIDTH,
- DEFAULT_DISPLAY_HEIGHT,
- HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER |
- GRALLOC_USAGE_HW_TEXTURE,
- "output"),
+ ExternalTexture>(sp<GraphicBuffer>::
+ make(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_TEXTURE,
+ "output"),
*mRE,
renderengine::impl::ExternalTexture::Usage::READABLE |
renderengine::impl::ExternalTexture::Usage::
@@ -251,12 +251,12 @@
uint32_t height) {
return std::make_shared<
renderengine::impl::
- ExternalTexture>(new GraphicBuffer(width, height,
- HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_TEXTURE,
- "input"),
+ ExternalTexture>(sp<GraphicBuffer>::
+ make(width, height, HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_TEXTURE,
+ "input"),
*mRE,
renderengine::impl::ExternalTexture::Usage::READABLE |
renderengine::impl::ExternalTexture::Usage::
@@ -285,10 +285,12 @@
}
std::shared_ptr<renderengine::ExternalTexture> allocateR8Buffer(int width, int height) {
- auto buffer = new GraphicBuffer(width, height, android::PIXEL_FORMAT_R_8, 1,
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_TEXTURE,
- "r8");
+ const auto kUsageFlags =
+ static_cast<uint64_t>(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_TEXTURE);
+ auto buffer =
+ sp<GraphicBuffer>::make(static_cast<uint32_t>(width), static_cast<uint32_t>(height),
+ android::PIXEL_FORMAT_R_8, 1u, kUsageFlags, "r8");
if (buffer->initCheck() != 0) {
// Devices are not required to support R8.
return nullptr;
@@ -1496,13 +1498,13 @@
auto buf = std::make_shared<
renderengine::impl::
- ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
- 1,
- GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER |
- GRALLOC_USAGE_HW_TEXTURE,
- "input"),
+ ExternalTexture>(sp<GraphicBuffer>::make(kGreyLevels, 1,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_TEXTURE,
+ "input"),
*mRE,
renderengine::impl::ExternalTexture::Usage::READABLE |
renderengine::impl::ExternalTexture::Usage::WRITEABLE);
@@ -1529,13 +1531,13 @@
mBuffer = std::make_shared<
renderengine::impl::
- ExternalTexture>(new GraphicBuffer(kGreyLevels, 1, HAL_PIXEL_FORMAT_RGBA_8888,
- 1,
- GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER |
- GRALLOC_USAGE_HW_TEXTURE,
- "output"),
+ ExternalTexture>(sp<GraphicBuffer>::make(kGreyLevels, 1,
+ HAL_PIXEL_FORMAT_RGBA_8888, 1,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER |
+ GRALLOC_USAGE_HW_TEXTURE,
+ "output"),
*mRE,
renderengine::impl::ExternalTexture::Usage::READABLE |
renderengine::impl::ExternalTexture::Usage::WRITEABLE);
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 9685189..909ded3 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -176,7 +176,7 @@
std::vector<renderengine::LayerSettings> layers;
std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared<
renderengine::impl::
- ExternalTexture>(new GraphicBuffer(), *mRenderEngine,
+ ExternalTexture>(sp<GraphicBuffer>::make(), *mRenderEngine,
renderengine::impl::ExternalTexture::Usage::READABLE |
renderengine::impl::ExternalTexture::Usage::WRITEABLE);
diff --git a/libs/sensor/fuzz/bittube_fuzzer/Android.bp b/libs/sensor/fuzz/bittube_fuzzer/Android.bp
new file mode 100644
index 0000000..7af22cc
--- /dev/null
+++ b/libs/sensor/fuzz/bittube_fuzzer/Android.bp
@@ -0,0 +1,51 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ */
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_fuzz {
+ name: "bittube_fuzzer",
+ srcs: [
+ "bittube_fuzzer.cpp",
+ ],
+ static_libs: [
+ ],
+ shared_libs: [
+ "libsensor",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ "liblog",
+ "libhardware",
+ "libpermission",
+ ],
+ export_shared_lib_headers: [
+ "libbinder",
+ "libpermission",
+ "libhardware",
+ ],
+ header_libs: [
+ ],
+}
diff --git a/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp b/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp
new file mode 100644
index 0000000..6f10a67
--- /dev/null
+++ b/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 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 <fuzzer/FuzzedDataProvider.h>
+
+#include <sensor/BitTube.h>
+#include <binder/Parcel.h>
+using namespace android;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ BitTube bittube(size);
+ Parcel parcel[5];
+ bittube.writeToParcel(parcel);
+ sp<BitTube> tube(new BitTube(size));
+ bittube.sendObjects<uint8_t>(tube, data, size);
+ uint8_t recvData[size];
+ for (int i = 0; i < size; i++) recvData[i] = fdp.ConsumeIntegral<uint8_t>();
+ bittube.recvObjects<uint8_t>(tube, recvData, size);
+
+ return 0;
+}
diff --git a/libs/sensor/fuzz/sensor_fuzzer/Android.bp b/libs/sensor/fuzz/sensor_fuzzer/Android.bp
new file mode 100644
index 0000000..685c549
--- /dev/null
+++ b/libs/sensor/fuzz/sensor_fuzzer/Android.bp
@@ -0,0 +1,47 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ */
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_fuzz {
+ name: "sensor_fuzzer",
+ srcs: [
+ "sensor_fuzzer.cpp",
+ ],
+ shared_libs: [
+ "libsensor",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ "liblog",
+ "libhardware",
+ "libpermission",
+ ],
+ export_shared_lib_headers: [
+ "libbinder",
+ "libpermission",
+ "libhardware",
+ ],
+}
diff --git a/libs/sensor/fuzz/sensor_fuzzer/sensor_fuzzer.cpp b/libs/sensor/fuzz/sensor_fuzzer/sensor_fuzzer.cpp
new file mode 100644
index 0000000..129f430
--- /dev/null
+++ b/libs/sensor/fuzz/sensor_fuzzer/sensor_fuzzer.cpp
@@ -0,0 +1,51 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 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 <fuzzer/FuzzedDataProvider.h>
+
+#include <sensor/Sensor.h>
+using namespace android;
+
+const int MAX_STR_LEN = 32;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ struct sensor_t sensor_type;
+ sensor_type.name = fdp.ConsumeBytesAsString(MAX_STR_LEN).c_str();
+ sensor_type.vendor = fdp.ConsumeBytesAsString(MAX_STR_LEN).c_str();
+ sensor_type.stringType = "";
+ sensor_type.requiredPermission = "";
+ sensor_type.version = fdp.ConsumeIntegral<int>();
+ sensor_type.handle = fdp.ConsumeIntegral<int>();
+ sensor_type.type = fdp.ConsumeIntegral<int>();
+ sensor_type.maxRange = fdp.ConsumeFloatingPoint<float>();
+ sensor_type.resolution = fdp.ConsumeFloatingPoint<float>();
+ sensor_type.power = fdp.ConsumeFloatingPoint<float>();
+ sensor_type.minDelay = fdp.ConsumeIntegral<int32_t>();
+ sensor_type.fifoReservedEventCount = fdp.ConsumeIntegral<uint32_t>();
+ sensor_type.fifoMaxEventCount = fdp.ConsumeIntegral<uint32_t>();
+ int halVersion = fdp.ConsumeIntegral<int>();
+ Sensor sensor1(&sensor_type, halVersion);
+ uint8_t buffer[size];
+ for (int i = 0; i < size; i++) buffer[i] = data[i];
+ sensor1.flatten(buffer, size);
+ std::vector<uint8_t> buffer1(sensor1.getFlattenedSize());
+ auto ab = sensor1.unflatten(buffer1.data(), buffer1.size());
+ return 0;
+}
+
diff --git a/libs/vibrator/include/vibrator/ExternalVibration.h b/libs/vibrator/include/vibrator/ExternalVibration.h
index c6eb3d1..760dbce 100644
--- a/libs/vibrator/include/vibrator/ExternalVibration.h
+++ b/libs/vibrator/include/vibrator/ExternalVibration.h
@@ -33,7 +33,6 @@
ExternalVibration(int32_t uid, std::string pkg, const audio_attributes_t& attrs,
sp<IExternalVibrationController> controller);
virtual ~ExternalVibration() = default;
- ExternalVibration(const ExternalVibration&) = default;
bool operator==(const ExternalVibration&) const;
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 120000
index 0000000..ee92d9e
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1 @@
+../../build/soong/scripts/rustfmt.toml
\ No newline at end of file
diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp
index 700074a..3ef5049 100644
--- a/services/audiomanager/IAudioManager.cpp
+++ b/services/audiomanager/IAudioManager.cpp
@@ -141,6 +141,17 @@
data.writeInt32((int32_t) sessionId);
return remote()->transact(PLAYER_SESSION_ID, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ virtual status_t portEvent(audio_port_handle_t portId, player_state_t event,
+ const std::unique_ptr<os::PersistableBundle>& extras) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
+ data.writeInt32((int32_t) portId);
+ data.writeInt32((int32_t) event);
+ // TODO: replace PersistableBundle with own struct
+ data.writeNullableParcelable(extras);
+ return remote()->transact(PORT_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
+ }
};
IMPLEMENT_META_INTERFACE(AudioManager, "android.media.IAudioService");
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 41878e3..29a0e4f 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -38,6 +38,7 @@
"-Wshadow",
"-Wshadow-field-in-constructor-modified",
"-Wshadow-uncaptured-local",
+ "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
sanitize: {
misc_undefined: ["bounds"],
@@ -56,7 +57,7 @@
filegroup {
name: "libinputflinger_sources",
srcs: [
- "InputClassifier.cpp",
+ "InputProcessor.cpp",
"InputCommonConverter.cpp",
"PreferStylusOverTouchBlocker.cpp",
"UnwantedInteractionBlocker.cpp",
@@ -168,3 +169,39 @@
"libinputflinger_headers",
],
}
+
+// This target will build everything 'input-related'. This could be useful for
+// large refactorings of the input code. This is similar to 'm checkbuild', but
+// just for input code.
+// Use 'm checkinput' to build, and then (optionally) use 'm installclean' to
+// remove any of the installed artifacts that you may not want on your actual
+// build.
+phony {
+ name: "checkinput",
+ required: [
+ // native targets
+ "libinput",
+ "libinputflinger",
+ "inputflinger_tests",
+ "inputflinger_benchmarks",
+ "libinput_tests",
+ "libpalmrejection_test",
+ "libandroid_runtime",
+ "libinputservice_test",
+ "Bug-115739809",
+ "StructLayout_test",
+ "inputflinger_latencytracker_fuzzer",
+
+ // Java/Kotlin targets
+ "CtsWindowManagerDeviceTestCases",
+ "InputTests",
+ "CtsHardwareTestCases",
+ "CtsInputTestCases",
+ "CtsViewTestCases",
+ "CtsWidgetTestCases",
+ "FrameworksCoreTests",
+ "FrameworksServicesTests",
+ "CtsSecurityTestCases",
+ "CtsSecurityBulletinHostTestCases",
+ ],
+}
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 2a3924b..dce327e 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -196,9 +196,20 @@
}
coords += StringPrintf("{%" PRIu32 ": ", i);
coords +=
- StringPrintf("id=%" PRIu32 " x=%.1f y=%.1f, pressure=%.1f", pointerProperties[i].id,
+ StringPrintf("id=%" PRIu32 " x=%.1f y=%.1f pressure=%.1f", pointerProperties[i].id,
pointerCoords[i].getX(), pointerCoords[i].getY(),
pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE));
+ const int32_t toolType = pointerProperties[i].toolType;
+ if (toolType != AMOTION_EVENT_TOOL_TYPE_FINGER) {
+ coords += StringPrintf(" toolType=%s", motionToolTypeToString(toolType));
+ }
+ const float major = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR);
+ const float minor = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR);
+ const float orientation = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
+ if (major != 0 || minor != 0) {
+ coords += StringPrintf(" major=%.1f minor=%.1f orientation=%.1f", major, minor,
+ orientation);
+ }
coords += "}";
}
return StringPrintf("NotifyMotionArgs(id=%" PRId32 ", eventTime=%" PRId64 ", deviceId=%" PRId32
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 9767cd9..9182503 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -55,14 +55,14 @@
/**
* The event flow is via the "InputListener" interface, as follows:
- * InputReader -> UnwantedInteractionBlocker -> InputClassifier -> InputDispatcher
+ * InputReader -> UnwantedInteractionBlocker -> InputProcessor -> InputDispatcher
*/
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = createInputDispatcher(dispatcherPolicy);
- mClassifier = std::make_unique<InputClassifier>(*mDispatcher);
- mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);
+ mProcessor = std::make_unique<InputProcessor>(*mDispatcher);
+ mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mProcessor);
mReader = createInputReader(readerPolicy, *mBlocker);
}
@@ -110,12 +110,12 @@
return *mReader;
}
-UnwantedInteractionBlockerInterface& InputManager::getUnwantedInteractionBlocker() {
+UnwantedInteractionBlockerInterface& InputManager::getBlocker() {
return *mBlocker;
}
-InputClassifierInterface& InputManager::getClassifier() {
- return *mClassifier;
+InputProcessorInterface& InputManager::getProcessor() {
+ return *mProcessor;
}
InputDispatcherInterface& InputManager::getDispatcher() {
@@ -125,7 +125,7 @@
void InputManager::monitor() {
mReader->monitor();
mBlocker->monitor();
- mClassifier->monitor();
+ mProcessor->monitor();
mDispatcher->monitor();
}
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 8aad35b..b40ab7f 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -21,7 +21,7 @@
* Native input manager.
*/
-#include "InputClassifier.h"
+#include "InputProcessor.h"
#include "InputReaderBase.h"
#include "include/UnwantedInteractionBlockerInterface.h"
@@ -52,10 +52,11 @@
* this could be a palm on the screen. This stage would alter the event stream to remove either
* partially (some of the pointers) or fully (all touches) the unwanted interaction. The events
* are processed on the InputReader thread, without any additional queue. The events are then
- * posted to the queue managed by the InputClassifier.
- * 3. The InputClassifier class starts a thread to communicate with the device-specific
- * classifiers. It then waits on the queue of events from UnwantedInteractionBlocker, applies
- * a classification to them, and queues them for the InputDispatcher.
+ * posted to the queue managed by the InputProcessor.
+ * 3. The InputProcessor class starts a thread to communicate with the device-specific
+ * IInputProcessor HAL. It then waits on the queue of events from UnwantedInteractionBlocker,
+ * processes the events (for example, applies a classification to the events), and queues them
+ * for the InputDispatcher.
* 4. The InputDispatcher class starts a thread that waits for new events on the
* previous queue and asynchronously dispatches them to applications.
*
@@ -83,10 +84,10 @@
virtual InputReaderInterface& getReader() = 0;
/* Gets the unwanted interaction blocker. */
- virtual UnwantedInteractionBlockerInterface& getUnwantedInteractionBlocker() = 0;
+ virtual UnwantedInteractionBlockerInterface& getBlocker() = 0;
- /* Gets the input classifier */
- virtual InputClassifierInterface& getClassifier() = 0;
+ /* Gets the input processor */
+ virtual InputProcessorInterface& getProcessor() = 0;
/* Gets the input dispatcher. */
virtual InputDispatcherInterface& getDispatcher() = 0;
@@ -108,8 +109,8 @@
status_t stop() override;
InputReaderInterface& getReader() override;
- UnwantedInteractionBlockerInterface& getUnwantedInteractionBlocker() override;
- InputClassifierInterface& getClassifier() override;
+ UnwantedInteractionBlockerInterface& getBlocker() override;
+ InputProcessorInterface& getProcessor() override;
InputDispatcherInterface& getDispatcher() override;
void monitor() override;
@@ -123,7 +124,7 @@
std::unique_ptr<UnwantedInteractionBlockerInterface> mBlocker;
- std::unique_ptr<InputClassifierInterface> mClassifier;
+ std::unique_ptr<InputProcessorInterface> mProcessor;
std::unique_ptr<InputDispatcherInterface> mDispatcher;
};
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputProcessor.cpp
similarity index 85%
rename from services/inputflinger/InputClassifier.cpp
rename to services/inputflinger/InputProcessor.cpp
index 21695c3..0749441 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputProcessor.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#define LOG_TAG "InputClassifier"
+#define LOG_TAG "InputProcessor"
-#include "InputClassifier.h"
+#include "InputProcessor.h"
#include "InputCommonConverter.h"
#include <android-base/stringprintf.h>
@@ -27,7 +27,7 @@
#include <algorithm>
#include <cmath>
#if defined(__linux__)
- #include <pthread.h>
+#include <pthread.h>
#endif
#include <unordered_set>
@@ -44,10 +44,10 @@
namespace android {
-//Max number of elements to store in mEvents.
+// Max number of elements to store in mEvents.
static constexpr size_t MAX_EVENTS = 5;
-template<class K, class V>
+template <class K, class V>
static V getValueForKey(const std::unordered_map<K, V>& map, K key, V defaultValue) {
auto it = map.find(key);
if (it == map.end()) {
@@ -123,15 +123,15 @@
// --- ClassifierEvent ---
-ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args) :
- type(ClassifierEventType::MOTION), args(std::move(args)) { };
-ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyDeviceResetArgs> args) :
- type(ClassifierEventType::DEVICE_RESET), args(std::move(args)) { };
-ClassifierEvent::ClassifierEvent(ClassifierEventType type, std::unique_ptr<NotifyArgs> args) :
- type(type), args(std::move(args)) { };
+ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyMotionArgs> args)
+ : type(ClassifierEventType::MOTION), args(std::move(args)){};
+ClassifierEvent::ClassifierEvent(std::unique_ptr<NotifyDeviceResetArgs> args)
+ : type(ClassifierEventType::DEVICE_RESET), args(std::move(args)){};
+ClassifierEvent::ClassifierEvent(ClassifierEventType type, std::unique_ptr<NotifyArgs> args)
+ : type(type), args(std::move(args)){};
-ClassifierEvent::ClassifierEvent(ClassifierEvent&& other) :
- type(other.type), args(std::move(other.args)) { };
+ClassifierEvent::ClassifierEvent(ClassifierEvent&& other)
+ : type(other.type), args(std::move(other.args)){};
ClassifierEvent& ClassifierEvent::operator=(ClassifierEvent&& other) {
type = other.type;
@@ -180,7 +180,7 @@
mHalThread = std::thread(&MotionClassifier::processEvents, this);
#if defined(__linux__)
// Set the thread name for debugging
- pthread_setname_np(mHalThread.native_handle(), "InputClassifier");
+ pthread_setname_np(mHalThread.native_handle(), "InputProcessor");
#endif
}
@@ -198,7 +198,7 @@
/**
* Obtain the classification from the HAL for a given MotionEvent.
- * Should only be called from the InputClassifier thread (mHalThread).
+ * Should only be called from the InputProcessor thread (mHalThread).
* Should not be called from the thread that notifyMotion runs on.
*
* There is no way to provide a timeout for a HAL call. So if the HAL takes too long
@@ -239,8 +239,8 @@
}
}
if (!halResponseOk) {
- ALOGE("Error communicating with InputClassifier HAL. "
- "Exiting MotionClassifier HAL thread");
+ ALOGE("Error communicating with InputProcessor HAL. "
+ "Exiting MotionClassifier HAL thread");
clearClassifications();
return;
}
@@ -262,14 +262,14 @@
}
void MotionClassifier::updateClassification(int32_t deviceId, nsecs_t eventTime,
- MotionClassification classification) {
+ MotionClassification classification) {
std::scoped_lock lock(mLock);
const nsecs_t lastDownTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0));
if (eventTime < lastDownTime) {
// HAL just finished processing an event that belonged to an earlier gesture,
// but new gesture is already in progress. Drop this classification.
ALOGW("Received late classification. Late by at least %" PRId64 " ms.",
- nanoseconds_to_milliseconds(lastDownTime - eventTime));
+ nanoseconds_to_milliseconds(lastDownTime - eventTime));
return;
}
mClassifications[deviceId] = classification;
@@ -319,14 +319,14 @@
/**
* Per-device reset. Clear the outstanding events that are going to be sent to HAL.
- * Request InputClassifier thread to call resetDevice for this particular device.
+ * Request InputProcessor thread to call resetDevice for this particular device.
*/
void MotionClassifier::reset(const NotifyDeviceResetArgs& args) {
int32_t deviceId = args.deviceId;
// Clear the pending events right away, to avoid unnecessary work done by the HAL.
mEvents.erase([deviceId](const ClassifierEvent& event) {
- std::optional<int32_t> eventDeviceId = event.getDeviceId();
- return eventDeviceId && (*eventDeviceId == deviceId);
+ std::optional<int32_t> eventDeviceId = event.getDeviceId();
+ return eventDeviceId && (*eventDeviceId == deviceId);
});
enqueueEvent(std::make_unique<NotifyDeviceResetArgs>(args));
}
@@ -334,23 +334,22 @@
void MotionClassifier::dump(std::string& dump) {
std::scoped_lock lock(mLock);
dump += StringPrintf(INDENT2 "mService connected: %s\n", mService ? "true" : "false");
- dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n",
- mEvents.size(), MAX_EVENTS);
+ dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n", mEvents.size(), MAX_EVENTS);
dump += INDENT2 "mClassifications, mLastDownTimes:\n";
dump += INDENT3 "Device Id\tClassification\tLast down time";
// Combine mClassifications and mLastDownTimes into a single table.
// Create a superset of device ids.
std::unordered_set<int32_t> deviceIds;
std::for_each(mClassifications.begin(), mClassifications.end(),
- [&deviceIds](auto pair){ deviceIds.insert(pair.first); });
+ [&deviceIds](auto pair) { deviceIds.insert(pair.first); });
std::for_each(mLastDownTimes.begin(), mLastDownTimes.end(),
- [&deviceIds](auto pair){ deviceIds.insert(pair.first); });
- for(int32_t deviceId : deviceIds) {
+ [&deviceIds](auto pair) { deviceIds.insert(pair.first); });
+ for (int32_t deviceId : deviceIds) {
const MotionClassification classification =
getValueForKey(mClassifications, deviceId, MotionClassification::NONE);
const nsecs_t downTime = getValueForKey(mLastDownTimes, deviceId, static_cast<nsecs_t>(0));
- dump += StringPrintf("\n" INDENT4 "%" PRId32 "\t%s\t%" PRId64,
- deviceId, motionClassificationToString(classification), downTime);
+ dump += StringPrintf("\n" INDENT4 "%" PRId32 "\t%s\t%" PRId64, deviceId,
+ motionClassificationToString(classification), downTime);
}
}
@@ -366,20 +365,20 @@
}
}
-// --- InputClassifier ---
+// --- InputProcessor ---
-InputClassifier::InputClassifier(InputListenerInterface& listener) : mQueuedListener(listener) {}
+InputProcessor::InputProcessor(InputListenerInterface& listener) : mQueuedListener(listener) {}
-void InputClassifier::onBinderDied(void* cookie) {
- InputClassifier* classifier = static_cast<InputClassifier*>(cookie);
- if (classifier == nullptr) {
+void InputProcessor::onBinderDied(void* cookie) {
+ InputProcessor* processor = static_cast<InputProcessor*>(cookie);
+ if (processor == nullptr) {
LOG_ALWAYS_FATAL("Cookie is not valid");
return;
}
- classifier->setMotionClassifierEnabled(false);
+ processor->setMotionClassifierEnabled(false);
}
-void InputClassifier::setMotionClassifierEnabled(bool enabled) {
+void InputProcessor::setMotionClassifierEnabled(bool enabled) {
std::scoped_lock lock(mLock);
if (enabled) {
ALOGI("Enabling motion classifier");
@@ -392,7 +391,7 @@
* and we can't continue because 'mInitializeMotionClassifier' will block in its
* destructor.
*/
- LOG_ALWAYS_FATAL("The thread to load IInputClassifier is stuck!");
+ LOG_ALWAYS_FATAL("The thread to load IInputProcessor is stuck!");
}
}
mInitializeMotionClassifier = std::async(std::launch::async, [this] {
@@ -416,19 +415,19 @@
}
}
-void InputClassifier::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
+void InputProcessor::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
// pass through
mQueuedListener.notifyConfigurationChanged(args);
mQueuedListener.flush();
}
-void InputClassifier::notifyKey(const NotifyKeyArgs* args) {
+void InputProcessor::notifyKey(const NotifyKeyArgs* args) {
// pass through
mQueuedListener.notifyKey(args);
mQueuedListener.flush();
}
-void InputClassifier::notifyMotion(const NotifyMotionArgs* args) {
+void InputProcessor::notifyMotion(const NotifyMotionArgs* args) {
{ // acquire lock
std::scoped_lock lock(mLock);
// MotionClassifier is only used for touch events, for now
@@ -444,25 +443,25 @@
mQueuedListener.flush();
}
-void InputClassifier::notifySensor(const NotifySensorArgs* args) {
+void InputProcessor::notifySensor(const NotifySensorArgs* args) {
// pass through
mQueuedListener.notifySensor(args);
mQueuedListener.flush();
}
-void InputClassifier::notifyVibratorState(const NotifyVibratorStateArgs* args) {
+void InputProcessor::notifyVibratorState(const NotifyVibratorStateArgs* args) {
// pass through
mQueuedListener.notifyVibratorState(args);
mQueuedListener.flush();
}
-void InputClassifier::notifySwitch(const NotifySwitchArgs* args) {
+void InputProcessor::notifySwitch(const NotifySwitchArgs* args) {
// pass through
mQueuedListener.notifySwitch(args);
mQueuedListener.flush();
}
-void InputClassifier::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
+void InputProcessor::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
{ // acquire lock
std::scoped_lock lock(mLock);
if (mMotionClassifier) {
@@ -475,13 +474,13 @@
mQueuedListener.flush();
}
-void InputClassifier::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
+void InputProcessor::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
// pass through
mQueuedListener.notifyPointerCaptureChanged(args);
mQueuedListener.flush();
}
-void InputClassifier::setMotionClassifierLocked(
+void InputProcessor::setMotionClassifierLocked(
std::unique_ptr<MotionClassifierInterface> motionClassifier) REQUIRES(mLock) {
if (motionClassifier == nullptr) {
// Destroy the ScopedDeathRecipient object, which will cause it to unlinkToDeath.
@@ -491,9 +490,9 @@
mMotionClassifier = std::move(motionClassifier);
}
-void InputClassifier::dump(std::string& dump) {
+void InputProcessor::dump(std::string& dump) {
std::scoped_lock lock(mLock);
- dump += "Input Classifier State:\n";
+ dump += "Input Processor State:\n";
dump += INDENT1 "Motion Classifier:\n";
if (mMotionClassifier) {
mMotionClassifier->dump(dump);
@@ -503,12 +502,11 @@
dump += "\n";
}
-void InputClassifier::monitor() {
+void InputProcessor::monitor() {
std::scoped_lock lock(mLock);
if (mMotionClassifier) mMotionClassifier->monitor();
}
-InputClassifier::~InputClassifier() {
-}
+InputProcessor::~InputProcessor() {}
} // namespace android
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputProcessor.h
similarity index 90%
rename from services/inputflinger/InputClassifier.h
rename to services/inputflinger/InputProcessor.h
index 9b31a3c..261e012 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputProcessor.h
@@ -61,8 +61,8 @@
*/
class MotionClassifierInterface {
public:
- MotionClassifierInterface() { }
- virtual ~MotionClassifierInterface() { }
+ MotionClassifierInterface() {}
+ virtual ~MotionClassifierInterface() {}
/**
* Based on the motion event described by NotifyMotionArgs,
* provide a MotionClassification for the current gesture.
@@ -92,7 +92,7 @@
* Base interface for an InputListener stage.
* Provides classification to events.
*/
-class InputClassifierInterface : public InputListenerInterface {
+class InputProcessorInterface : public InputListenerInterface {
public:
virtual void setMotionClassifierEnabled(bool enabled) = 0;
/**
@@ -104,8 +104,8 @@
/** Called by the heartbeat to ensure that the classifier has not deadlocked. */
virtual void monitor() = 0;
- InputClassifierInterface() { }
- virtual ~InputClassifierInterface() { }
+ InputProcessorInterface() {}
+ virtual ~InputProcessorInterface() {}
};
// --- Implementations ---
@@ -124,10 +124,10 @@
};
/**
- * Implementation of MotionClassifierInterface that calls the InputClassifier HAL
+ * Implementation of MotionClassifierInterface that calls the InputProcessor HAL
* in order to determine the classification for the current gesture.
*
- * The InputClassifier HAL may keep track of the entire gesture in order to determine
+ * The InputProcessor HAL may keep track of the entire gesture in order to determine
* the classification, and may be hardware-specific. It may use the data in
* NotifyMotionArgs::videoFrames field to drive the classification decisions.
* The HAL is called from a separate thread.
@@ -174,20 +174,20 @@
*/
void enqueueEvent(ClassifierEvent&& event);
/**
- * Thread that will communicate with InputClassifier HAL.
- * This should be the only thread that communicates with InputClassifier HAL,
+ * Thread that will communicate with InputProcessor HAL.
+ * This should be the only thread that communicates with InputProcessor HAL,
* because this thread is allowed to block on the HAL calls.
*/
std::thread mHalThread;
/**
- * Process events and call the InputClassifier HAL
+ * Process events and call the InputProcessor HAL
*/
void processEvents();
/**
* Access to the InputProcessor HAL. May be null if init() hasn't completed yet.
* When init() successfully completes, mService is guaranteed to remain non-null and to not
* change its value until MotionClassifier is destroyed.
- * This variable is *not* guarded by mLock in the InputClassifier thread, because
+ * This variable is *not* guarded by mLock in the InputProcessor thread, because
* that thread knows exactly when this variable is initialized.
* When accessed in any other thread, mService is checked for nullness with a lock.
*/
@@ -197,8 +197,8 @@
* Per-device input classifications. Should only be accessed using the
* getClassification / setClassification methods.
*/
- std::unordered_map<int32_t /*deviceId*/, MotionClassification>
- mClassifications GUARDED_BY(mLock);
+ std::unordered_map<int32_t /*deviceId*/, MotionClassification> mClassifications
+ GUARDED_BY(mLock);
/**
* Set the current classification for a given device.
*/
@@ -208,7 +208,7 @@
*/
MotionClassification getClassification(int32_t deviceId);
void updateClassification(int32_t deviceId, nsecs_t eventTime,
- MotionClassification classification);
+ MotionClassification classification);
/**
* Clear all current classifications
*/
@@ -217,7 +217,7 @@
* Per-device times when the last ACTION_DOWN was received.
* Used to reject late classifications that do not belong to the current gesture.
*
- * Accessed indirectly by both InputClassifier thread and the thread that receives notifyMotion.
+ * Accessed indirectly by both InputProcessor thread and the thread that receives notifyMotion.
*/
std::unordered_map<int32_t /*deviceId*/, nsecs_t /*downTime*/> mLastDownTimes GUARDED_BY(mLock);
@@ -226,7 +226,7 @@
void clearDeviceState(int32_t deviceId);
/**
- * Exit the InputClassifier HAL thread.
+ * Exit the InputProcessor HAL thread.
* Useful for tests to ensure proper cleanup.
*/
void requestExit();
@@ -237,14 +237,14 @@
};
/**
- * Implementation of the InputClassifierInterface.
+ * Implementation of the InputProcessorInterface.
* Represents a separate stage of input processing. All of the input events go through this stage.
* Acts as a passthrough for all input events except for motion events.
* The events of motion type are sent to MotionClassifier.
*/
-class InputClassifier : public InputClassifierInterface {
+class InputProcessor : public InputProcessorInterface {
public:
- explicit InputClassifier(InputListenerInterface& listener);
+ explicit InputProcessor(InputListenerInterface& listener);
void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
void notifyKey(const NotifyKeyArgs* args) override;
@@ -258,7 +258,7 @@
void dump(std::string& dump) override;
void monitor() override;
- ~InputClassifier();
+ ~InputProcessor();
// Called from InputManager
void setMotionClassifierEnabled(bool enabled) override;
diff --git a/services/inputflinger/InputThread.cpp b/services/inputflinger/InputThread.cpp
index b87f7a1..e2e64f9 100644
--- a/services/inputflinger/InputThread.cpp
+++ b/services/inputflinger/InputThread.cpp
@@ -41,7 +41,7 @@
InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)
: mName(name), mThreadWake(wake) {
- mThread = new InputThreadImpl(loop);
+ mThread = sp<InputThreadImpl>::make(loop);
mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
}
diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp
index a8e495f..4e0f0c3 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.cpp
+++ b/services/inputflinger/UnwantedInteractionBlocker.cpp
@@ -39,6 +39,30 @@
namespace android {
+/**
+ * Log detailed debug messages about each inbound motion event notification to the blocker.
+ * Enable this via "adb shell setprop log.tag.UnwantedInteractionBlockerInboundMotion DEBUG"
+ * (requires restart)
+ */
+const bool DEBUG_INBOUND_MOTION =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "InboundMotion", ANDROID_LOG_INFO);
+
+/**
+ * Log detailed debug messages about each outbound motion event processed by the blocker.
+ * Enable this via "adb shell setprop log.tag.UnwantedInteractionBlockerOutboundMotion DEBUG"
+ * (requires restart)
+ */
+const bool DEBUG_OUTBOUND_MOTION =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "OutboundMotion", ANDROID_LOG_INFO);
+
+/**
+ * Log the data sent to the model and received back from the model.
+ * Enable this via "adb shell setprop log.tag.UnwantedInteractionBlockerModel DEBUG"
+ * (requires restart)
+ */
+const bool DEBUG_MODEL =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Model", ANDROID_LOG_INFO);
+
// Category (=namespace) name for the input settings that are applied at boot time
static const char* INPUT_NATIVE_BOOT = "input_native_boot";
/**
@@ -58,8 +82,7 @@
}
static ::base::TimeTicks toChromeTimestamp(nsecs_t eventTime) {
- return ::base::TimeTicks::UnixEpoch() +
- ::base::Milliseconds(static_cast<float>(ns2ms(eventTime)));
+ return ::base::TimeTicks::UnixEpoch() + ::base::TimeDelta::FromNanosecondsD(eventTime);
}
/**
@@ -69,8 +92,8 @@
static bool isPalmRejectionEnabled() {
std::string value = toLower(
server_configurable_flags::GetServerConfigurableFlag(INPUT_NATIVE_BOOT,
- PALM_REJECTION_ENABLED, "false"));
- if (value == "true" || value == "1") {
+ PALM_REJECTION_ENABLED, "0"));
+ if (value == "1") {
return true;
}
return false;
@@ -310,6 +333,7 @@
}
void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) {
+ ALOGD_IF(DEBUG_INBOUND_MOTION, "%s: %s", __func__, args->dump().c_str());
{ // acquire lock
std::scoped_lock lock(mLock);
const std::vector<NotifyMotionArgs> processedArgs =
@@ -323,17 +347,22 @@
mQueuedListener.flush();
}
+void UnwantedInteractionBlocker::enqueueOutboundMotionLocked(const NotifyMotionArgs& args) {
+ ALOGD_IF(DEBUG_OUTBOUND_MOTION, "%s: %s", __func__, args.dump().c_str());
+ mQueuedListener.notifyMotion(&args);
+}
+
void UnwantedInteractionBlocker::notifyMotionLocked(const NotifyMotionArgs* args) {
auto it = mPalmRejectors.find(args->deviceId);
const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args->source);
if (!sendToPalmRejector) {
- mQueuedListener.notifyMotion(args);
+ enqueueOutboundMotionLocked(*args);
return;
}
std::vector<NotifyMotionArgs> processedArgs = it->second.processMotion(*args);
for (const NotifyMotionArgs& loopArgs : processedArgs) {
- mQueuedListener.notifyMotion(&loopArgs);
+ enqueueOutboundMotionLocked(loopArgs);
}
}
@@ -617,8 +646,18 @@
getTouches(args, mDeviceInfo, oldSlotState, mSlotState);
::base::TimeTicks chromeTimestamp = toChromeTimestamp(args.eventTime);
+ if (DEBUG_MODEL) {
+ std::stringstream touchesStream;
+ for (const ::ui::InProgressTouchEvdev& touch : touches) {
+ touchesStream << touch.tracking_id << " : " << touch << "\n";
+ }
+ ALOGD("Filter: touches = %s", touchesStream.str().c_str());
+ }
mPalmDetectionFilter->Filter(touches, chromeTimestamp, &slotsToHold, &slotsToSuppress);
+ ALOGD_IF(DEBUG_MODEL, "Response: slotsToHold = %s, slotsToSuppress = %s",
+ slotsToHold.to_string().c_str(), slotsToSuppress.to_string().c_str());
+
// Now that we know which slots should be suppressed, let's convert those to pointer id's.
std::set<int32_t> oldSuppressedIds;
std::swap(oldSuppressedIds, mSuppressedPointerIds);
diff --git a/services/inputflinger/UnwantedInteractionBlocker.h b/services/inputflinger/UnwantedInteractionBlocker.h
index a433764..8ff9658 100644
--- a/services/inputflinger/UnwantedInteractionBlocker.h
+++ b/services/inputflinger/UnwantedInteractionBlocker.h
@@ -101,6 +101,9 @@
std::map<int32_t /*deviceId*/, PalmRejector> mPalmRejectors GUARDED_BY(mLock);
// TODO(b/210159205): delete this when simultaneous stylus and touch is supported
void notifyMotionLocked(const NotifyMotionArgs* args) REQUIRES(mLock);
+
+ // Call this function for outbound events so that they can be logged when logging is enabled.
+ void enqueueOutboundMotionLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
};
class SlotState {
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index c9ea068..12eeea6 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -260,14 +260,15 @@
static void benchmarkNotifyMotion(benchmark::State& state) {
// Create dispatcher
- sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy();
+ sp<FakeInputDispatcherPolicy> fakePolicy = sp<FakeInputDispatcherPolicy>::make();
InputDispatcher dispatcher(fakePolicy);
dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
dispatcher.start();
// Create a window that will receive motion events
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, dispatcher, "Fake Window");
dispatcher.setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -294,14 +295,15 @@
static void benchmarkInjectMotion(benchmark::State& state) {
// Create dispatcher
- sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy();
+ sp<FakeInputDispatcherPolicy> fakePolicy = sp<FakeInputDispatcherPolicy>::make();
InputDispatcher dispatcher(fakePolicy);
dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
dispatcher.start();
// Create a window that will receive motion events
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, dispatcher, "Fake Window");
dispatcher.setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -327,14 +329,15 @@
static void benchmarkOnWindowInfosChanged(benchmark::State& state) {
// Create dispatcher
- sp<FakeInputDispatcherPolicy> fakePolicy = new FakeInputDispatcherPolicy();
+ sp<FakeInputDispatcherPolicy> fakePolicy = sp<FakeInputDispatcherPolicy>::make();
InputDispatcher dispatcher(fakePolicy);
dispatcher.setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
dispatcher.start();
// Create a window
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window = new FakeWindowHandle(application, dispatcher, "Fake Window");
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, dispatcher, "Fake Window");
std::vector<gui::WindowInfo> windowInfos{*window->getInfo()};
gui::DisplayInfo info;
diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp
index 4da846b..85dcf8f 100644
--- a/services/inputflinger/dispatcher/FocusResolver.cpp
+++ b/services/inputflinger/dispatcher/FocusResolver.cpp
@@ -39,7 +39,7 @@
return it != mFocusedWindowTokenByDisplay.end() ? it->second.second : nullptr;
}
-std::optional<FocusRequest> FocusResolver::getFocusRequest(int32_t displayId) {
+std::optional<FocusRequest> FocusResolver::getFocusRequest(int32_t displayId) const {
auto it = mFocusRequestByDisplay.find(displayId);
return it != mFocusRequestByDisplay.end() ? std::make_optional<>(it->second) : std::nullopt;
}
diff --git a/services/inputflinger/dispatcher/FocusResolver.h b/services/inputflinger/dispatcher/FocusResolver.h
index 6d11a77..8a6dfa4 100644
--- a/services/inputflinger/dispatcher/FocusResolver.h
+++ b/services/inputflinger/dispatcher/FocusResolver.h
@@ -62,6 +62,7 @@
std::optional<FocusResolver::FocusChanges> setFocusedWindow(
const android::gui::FocusRequest& request,
const std::vector<sp<android::gui::WindowInfoHandle>>& windows);
+ std::optional<android::gui::FocusRequest> getFocusRequest(int32_t displayId) const;
// Display has been removed from the system, clean up old references.
void displayRemoved(int32_t displayId);
@@ -112,7 +113,6 @@
std::optional<FocusResolver::FocusChanges> updateFocusedWindow(
int32_t displayId, const std::string& reason, const sp<IBinder>& token,
const std::string& tokenName = "");
- std::optional<android::gui::FocusRequest> getFocusRequest(int32_t displayId);
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4516558..b52e312 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -555,10 +555,10 @@
mLatencyAggregator(),
mLatencyTracker(&mLatencyAggregator),
kPerDisplayTouchModeEnabled(mPolicy->isPerDisplayTouchModeEnabled()) {
- mLooper = new Looper(false);
+ mLooper = sp<Looper>::make(false);
mReporter = createInputReporter();
- mWindowInfoListener = new DispatcherWindowListener(*this);
+ mWindowInfoListener = sp<DispatcherWindowListener>::make(*this);
SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);
mKeyRepeatState.lastKeyEntry = nullptr;
@@ -659,6 +659,13 @@
if (focusedWindowHandle != nullptr) {
return; // We now have a focused window. No need for ANR.
}
+ std::optional<FocusRequest> pendingRequest =
+ mFocusResolver.getFocusRequest(mAwaitedApplicationDisplayId);
+ if (pendingRequest.has_value() && onAnrLocked(*pendingRequest)) {
+ // We don't have a focusable window but we know which window should have
+ // been focused. Blame that process in case it doesn't belong to the focused app.
+ return;
+ }
onAnrLocked(mAwaitedFocusedApplication);
}
@@ -2207,10 +2214,7 @@
// Update the temporary touch state.
BitSet32 pointerIds;
- if (isSplit) {
- uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
- pointerIds.markBit(pointerId);
- }
+ pointerIds.markBit(entry.pointerProperties[pointerIndex].id);
tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds,
entry.eventTime);
@@ -2297,9 +2301,7 @@
}
BitSet32 pointerIds;
- if (isSplit) {
- pointerIds.markBit(entry.pointerProperties[0].id);
- }
+ pointerIds.markBit(entry.pointerProperties[0].id);
tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds,
entry.eventTime);
}
@@ -2477,21 +2479,28 @@
}
} else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
// One pointer went up.
- if (isSplit) {
- int32_t pointerIndex = getMotionEventActionPointerIndex(action);
- uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
+ int32_t pointerIndex = getMotionEventActionPointerIndex(action);
+ uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
- for (size_t i = 0; i < tempTouchState.windows.size();) {
- TouchedWindow& touchedWindow = tempTouchState.windows[i];
- if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {
- touchedWindow.pointerIds.clearBit(pointerId);
- if (touchedWindow.pointerIds.isEmpty()) {
- tempTouchState.windows.erase(tempTouchState.windows.begin() + i);
- continue;
- }
- }
- i += 1;
+ for (size_t i = 0; i < tempTouchState.windows.size();) {
+ TouchedWindow& touchedWindow = tempTouchState.windows[i];
+ touchedWindow.pointerIds.clearBit(pointerId);
+ if (touchedWindow.pointerIds.isEmpty()) {
+ tempTouchState.windows.erase(tempTouchState.windows.begin() + i);
+ continue;
}
+ i += 1;
+ }
+ } else if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) {
+ // If no split, we suppose all touched windows should receive pointer down.
+ const int32_t pointerIndex = getMotionEventActionPointerIndex(action);
+ for (size_t i = 0; i < tempTouchState.windows.size(); i++) {
+ TouchedWindow& touchedWindow = tempTouchState.windows[i];
+ // Ignore drag window for it should just track one pointer.
+ if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) {
+ continue;
+ }
+ touchedWindow.pointerIds.markBit(entry.pointerProperties[pointerIndex].id);
}
}
@@ -5121,14 +5130,13 @@
// Store the dragging window.
if (isDragDrop) {
- if (pointerIds.count() > 1) {
- ALOGW("The drag and drop cannot be started when there is more than 1 pointer on the"
- " window.");
+ if (pointerIds.count() != 1) {
+ ALOGW("The drag and drop cannot be started when there is no pointer or more than 1"
+ " pointer on the window.");
return false;
}
- // If the window didn't not support split or the source is mouse, the pointerIds count
- // would be 0, so we have to track the pointer 0.
- const int32_t id = pointerIds.count() == 0 ? 0 : pointerIds.firstMarkedBit();
+ // Track the pointer id for drag window and generate the drag state.
+ const int32_t id = pointerIds.firstMarkedBit();
mDragState = std::make_unique<DragState>(toWindowHandle, id);
}
@@ -5509,7 +5517,7 @@
const sp<IBinder>& token = serverChannel->getConnectionToken();
int fd = serverChannel->getFd();
sp<Connection> connection =
- new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator);
+ sp<Connection>::make(std::move(serverChannel), false /*monitor*/, mIdGenerator);
if (mConnectionsByToken.find(token) != mConnectionsByToken.end()) {
ALOGE("Created a new connection, but the token %p is already known", token.get());
@@ -5519,7 +5527,8 @@
std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
this, std::placeholders::_1, token);
- mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);
+ mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback),
+ nullptr);
} // release lock
// Wake the looper because some connections have changed.
@@ -5545,7 +5554,8 @@
<< " without a specified display.";
}
- sp<Connection> connection = new Connection(serverChannel, true /*monitor*/, mIdGenerator);
+ sp<Connection> connection =
+ sp<Connection>::make(serverChannel, true /*monitor*/, mIdGenerator);
const sp<IBinder>& token = serverChannel->getConnectionToken();
const int fd = serverChannel->getFd();
@@ -5558,7 +5568,8 @@
mGlobalMonitorsByDisplay[displayId].emplace_back(serverChannel, pid);
- mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);
+ mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback),
+ nullptr);
}
// Wake the looper because some connections have changed.
@@ -5844,6 +5855,25 @@
postCommandLocked(std::move(command));
}
+bool InputDispatcher::onAnrLocked(const android::gui::FocusRequest& pendingFocusRequest) {
+ if (pendingFocusRequest.token == nullptr) {
+ return false;
+ }
+
+ const std::string reason = android::base::StringPrintf("%s is not focusable.",
+ pendingFocusRequest.windowName.c_str());
+ updateLastAnrStateLocked(pendingFocusRequest.windowName, reason);
+ sp<Connection> connection = getConnectionLocked(pendingFocusRequest.token);
+ if (connection != nullptr) {
+ processConnectionUnresponsiveLocked(*connection, std::move(reason));
+ // Stop waking up for events on this connection, it is already unresponsive
+ cancelEventsForAnrLocked(connection);
+ } else {
+ sendWindowUnresponsiveCommandLocked(pendingFocusRequest.token, std::nullopt, reason);
+ }
+ return true;
+}
+
void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
if (connection == nullptr) {
LOG_ALWAYS_FATAL("Caller must check for nullness");
@@ -6366,11 +6396,18 @@
std::unordered_map<int32_t, std::vector<sp<WindowInfoHandle>>> handlesPerDisplay;
for (const auto& info : windowInfos) {
handlesPerDisplay.emplace(info.displayId, std::vector<sp<WindowInfoHandle>>());
- handlesPerDisplay[info.displayId].push_back(new WindowInfoHandle(info));
+ handlesPerDisplay[info.displayId].push_back(sp<WindowInfoHandle>::make(info));
}
{ // acquire lock
std::scoped_lock _l(mLock);
+
+ // Ensure that we have an entry created for all existing displays so that if a displayId has
+ // no windows, we can tell that the windows were removed from the display.
+ for (const auto& [displayId, _] : mWindowHandlesByDisplay) {
+ handlesPerDisplay[displayId];
+ }
+
mDisplayInfos.clear();
for (const auto& displayInfo : displayInfos) {
mDisplayInfos.emplace(displayInfo.displayId, displayInfo);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index be619ae..dc6dd5c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -658,6 +658,7 @@
void sendDropWindowCommandLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock);
void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock);
+ bool onAnrLocked(const android::gui::FocusRequest& pendingFocusRequest) REQUIRES(mLock);
void updateLastAnrStateLocked(const sp<android::gui::WindowInfoHandle>& window,
const std::string& reason) REQUIRES(mLock);
void updateLastAnrStateLocked(const InputApplicationHandle& application,
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
index d39113b..2df97d9 100644
--- a/services/inputflinger/dispatcher/InputTarget.cpp
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -43,8 +43,8 @@
}
void InputTarget::addPointers(BitSet32 newPointerIds, const ui::Transform& transform) {
- // The pointerIds can be empty, but still a valid InputTarget. This can happen for Monitors
- // and non splittable windows since we will just use all the pointers from the input event.
+ // The pointerIds can be empty, but still a valid InputTarget. This can happen when there is no
+ // valid pointer property from the input event.
if (newPointerIds.isEmpty()) {
setDefaultPointerTransform(transform);
return;
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index 0962d0c..a7839db 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -29,7 +29,7 @@
struct TouchedWindow {
sp<gui::WindowInfoHandle> windowHandle;
int32_t targetFlags;
- BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set
+ BitSet32 pointerIds;
bool isPilferingPointers = false;
// Time at which the first action down occurred on this window.
// NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE scenario.
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index a17d2c0..bfa44ac 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1310,7 +1310,8 @@
if (!identifier.uniqueId.empty()) {
rawDescriptor += "uniqueId:";
rawDescriptor += identifier.uniqueId;
- } else if (identifier.nonce != 0) {
+ }
+ if (identifier.nonce != 0) {
rawDescriptor += StringPrintf("nonce:%04x", identifier.nonce);
}
@@ -1338,16 +1339,20 @@
// of Android. In practice we sometimes get devices that cannot be uniquely
// identified. In this case we enforce uniqueness between connected devices.
// Ideally, we also want the descriptor to be short and relatively opaque.
+ // Note that we explicitly do not use the path or location for external devices
+ // as their path or location will change as they are plugged/unplugged or moved
+ // to different ports. We do fallback to using name and location in the case of
+ // internal devices which are detected by the vendor and product being 0 in
+ // generateDescriptor. If two identical descriptors are detected we will fallback
+ // to using a 'nonce' and incrementing it until the new descriptor no longer has
+ // a match with any existing descriptors.
identifier.nonce = 0;
std::string rawDescriptor = generateDescriptor(identifier);
- if (identifier.uniqueId.empty()) {
- // If it didn't have a unique id check for conflicts and enforce
- // uniqueness if necessary.
- while (getDeviceByDescriptorLocked(identifier.descriptor) != nullptr) {
- identifier.nonce++;
- rawDescriptor = generateDescriptor(identifier);
- }
+ // Enforce that the generated descriptor is unique.
+ while (hasDeviceWithDescriptorLocked(identifier.descriptor)) {
+ identifier.nonce++;
+ rawDescriptor = generateDescriptor(identifier);
}
ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.c_str(),
identifier.descriptor.c_str());
@@ -1422,13 +1427,22 @@
return vibrators;
}
-EventHub::Device* EventHub::getDeviceByDescriptorLocked(const std::string& descriptor) const {
- for (const auto& [id, device] : mDevices) {
+/**
+ * Checks both mDevices and mOpeningDevices for a device with the descriptor passed.
+ */
+bool EventHub::hasDeviceWithDescriptorLocked(const std::string& descriptor) const {
+ for (const auto& device : mOpeningDevices) {
if (descriptor == device->identifier.descriptor) {
- return device.get();
+ return true;
}
}
- return nullptr;
+
+ for (const auto& [id, device] : mDevices) {
+ if (descriptor == device->identifier.descriptor) {
+ return true;
+ }
+ }
+ return false;
}
EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 79901f0..11a2dbe 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -38,6 +38,26 @@
namespace android {
+/**
+ * Determines if the identifiers passed are a sub-devices. Sub-devices are physical devices
+ * that expose multiple input device paths such a keyboard that also has a touchpad input.
+ * These are separate devices with unique descriptors in EventHub, but InputReader should
+ * create a single InputDevice for them.
+ * Sub-devices are detected by the following criteria:
+ * 1. The vendor, product, bus, version, and unique id match
+ * 2. The location matches. The location is used to distinguish a single device with multiple
+ * inputs versus the same device plugged into multiple ports.
+ */
+
+static bool isSubDevice(const InputDeviceIdentifier& identifier1,
+ const InputDeviceIdentifier& identifier2) {
+ return (identifier1.vendor == identifier2.vendor &&
+ identifier1.product == identifier2.product && identifier1.bus == identifier2.bus &&
+ identifier1.version == identifier2.version &&
+ identifier1.uniqueId == identifier2.uniqueId &&
+ identifier1.location == identifier2.location);
+}
+
// --- InputReader ---
InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
@@ -270,8 +290,9 @@
std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
int32_t eventHubId, const InputDeviceIdentifier& identifier) {
auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) {
- return devicePair.second->getDescriptor().size() && identifier.descriptor.size() &&
- devicePair.second->getDescriptor() == identifier.descriptor;
+ const InputDeviceIdentifier identifier2 =
+ devicePair.second->getDeviceInfo().getIdentifier();
+ return isSubDevice(identifier, identifier2);
});
std::shared_ptr<InputDevice> device;
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 79188aa..4733ecb 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -652,7 +652,6 @@
base::Result<void> readNotifyLocked() REQUIRES(mLock);
void handleNotifyEventLocked(const inotify_event&) REQUIRES(mLock);
- Device* getDeviceByDescriptorLocked(const std::string& descriptor) const REQUIRES(mLock);
Device* getDeviceLocked(int32_t deviceId) const REQUIRES(mLock);
Device* getDeviceByPathLocked(const std::string& devicePath) const REQUIRES(mLock);
/**
@@ -662,6 +661,9 @@
Device* getDeviceByFdLocked(int fd) const REQUIRES(mLock);
int32_t getNextControllerNumberLocked(const std::string& name) REQUIRES(mLock);
+
+ bool hasDeviceWithDescriptorLocked(const std::string& descriptor) const REQUIRES(mLock);
+
void releaseControllerNumberLocked(int32_t num) REQUIRES(mLock);
void reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier,
ftl::Flags<InputDeviceClass> classes) REQUIRES(mLock);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index c1111f2..17ee54f 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -46,6 +46,8 @@
static const float MIN_FREEFORM_GESTURE_WIDTH_IN_MILLIMETER = 30;
// --- Static Definitions ---
+static const DisplayViewport kUninitializedViewport;
+
template <typename T>
inline static void swap(T& a, T& b) {
T temp = a;
@@ -392,6 +394,10 @@
}
if (changes && resetNeeded) {
+ // If the device needs to be reset, cancel any ongoing gestures and reset the state.
+ cancelTouch(when, when);
+ reset(when);
+
// Send reset, unless this is the first time the device has been configured,
// in which case the reader will call reset itself after all mappers are ready.
NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
@@ -882,7 +888,7 @@
}
void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) {
- DeviceMode oldDeviceMode = mDeviceMode;
+ const DeviceMode oldDeviceMode = mDeviceMode;
resolveExternalStylusPresence();
@@ -911,31 +917,24 @@
mDeviceMode = DeviceMode::UNSCALED;
}
- // Ensure we have valid X and Y axes.
+ const std::optional<DisplayViewport> newViewportOpt = findViewport();
+
+ // Ensure the device is valid and can be used.
if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
ALOGW("Touch device '%s' did not report support for X or Y axis! "
"The device will be inoperable.",
getDeviceName().c_str());
mDeviceMode = DeviceMode::DISABLED;
- return;
- }
-
- // Get associated display dimensions.
- std::optional<DisplayViewport> newViewport = findViewport();
- if (!newViewport) {
+ } else if (!newViewportOpt) {
ALOGI("Touch device '%s' could not query the properties of its associated "
"display. The device will be inoperable until the display size "
"becomes available.",
getDeviceName().c_str());
mDeviceMode = DeviceMode::DISABLED;
- return;
- }
-
- if (!newViewport->isActive) {
+ } else if (!newViewportOpt->isActive) {
ALOGI("Disabling %s (device %i) because the associated viewport is not active",
getDeviceName().c_str(), getDeviceId());
mDeviceMode = DeviceMode::DISABLED;
- return;
}
// Raw width and height in the natural orientation.
@@ -947,11 +946,13 @@
const float rawMeanResolution =
(rawXResolution > 0 && rawYResolution > 0) ? (rawXResolution + rawYResolution) / 2 : 0;
- const bool viewportChanged = mViewport != *newViewport;
+ const DisplayViewport& newViewport = newViewportOpt.value_or(kUninitializedViewport);
+ const bool viewportChanged = mViewport != newViewport;
bool skipViewportUpdate = false;
if (viewportChanged) {
- const bool viewportOrientationChanged = mViewport.orientation != newViewport->orientation;
- mViewport = *newViewport;
+ const bool viewportOrientationChanged = mViewport.orientation != newViewport.orientation;
+ const bool viewportDisplayIdChanged = mViewport.displayId != newViewport.displayId;
+ mViewport = newViewport;
if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) {
// Convert rotated viewport to the natural orientation.
@@ -1026,8 +1027,9 @@
: getInverseRotation(mViewport.orientation);
// For orientation-aware devices that work in the un-rotated coordinate space, the
// viewport update should be skipped if it is only a change in the orientation.
- skipViewportUpdate = mParameters.orientationAware && mDisplayWidth == oldDisplayWidth &&
- mDisplayHeight == oldDisplayHeight && viewportOrientationChanged;
+ skipViewportUpdate = !viewportDisplayIdChanged && mParameters.orientationAware &&
+ mDisplayWidth == oldDisplayWidth && mDisplayHeight == oldDisplayHeight &&
+ viewportOrientationChanged;
// Apply the input device orientation for the device.
mInputDeviceOrientation =
@@ -1112,10 +1114,6 @@
mPointerGestureMaxSwipeWidth =
std::max(mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal,
minFreeformGestureWidth);
-
- // Abort current pointer usages because the state has changed.
- const nsecs_t readTime = when; // synthetic event
- abortPointerUsage(when, readTime, 0 /*policyFlags*/);
}
// Inform the dispatcher about the changes.
@@ -1960,6 +1958,10 @@
}
void TouchInputMapper::abortTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+ if (mCurrentMotionAborted) {
+ // Current motion event was already aborted.
+ return;
+ }
BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
if (!currentIdBits.isEmpty()) {
int32_t metaState = getContext()->getGlobalMetaState();
diff --git a/services/inputflinger/reporter/InputReporter.cpp b/services/inputflinger/reporter/InputReporter.cpp
index b591d3f..6f1eef6 100644
--- a/services/inputflinger/reporter/InputReporter.cpp
+++ b/services/inputflinger/reporter/InputReporter.cpp
@@ -35,7 +35,7 @@
}
sp<InputReporterInterface> createInputReporter() {
- return new InputReporter();
+ return sp<InputReporter>::make();
}
} // namespace android
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 76a7c19..6da2145 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -41,8 +41,8 @@
"EventHub_test.cpp",
"FocusResolver_test.cpp",
"IInputFlingerQuery.aidl",
- "InputClassifier_test.cpp",
- "InputClassifierConverter_test.cpp",
+ "InputProcessor_test.cpp",
+ "InputProcessorConverter_test.cpp",
"InputDispatcher_test.cpp",
"InputReader_test.cpp",
"InputFlingerService_test.cpp",
diff --git a/services/inputflinger/tests/AnrTracker_test.cpp b/services/inputflinger/tests/AnrTracker_test.cpp
index b561da1..f8be48a 100644
--- a/services/inputflinger/tests/AnrTracker_test.cpp
+++ b/services/inputflinger/tests/AnrTracker_test.cpp
@@ -40,8 +40,8 @@
TEST(AnrTrackerTest, MultipleEntries_RemoveToken) {
AnrTracker tracker;
- sp<IBinder> token1 = new BBinder();
- sp<IBinder> token2 = new BBinder();
+ sp<IBinder> token1 = sp<BBinder>::make();
+ sp<IBinder> token2 = sp<BBinder>::make();
tracker.insert(1, token1);
tracker.insert(2, token2);
@@ -90,8 +90,8 @@
TEST(AnrTrackerTest, MultipleTokens_MaintainsOrder) {
AnrTracker tracker;
- sp<IBinder> token1 = new BBinder();
- sp<IBinder> token2 = new BBinder();
+ sp<IBinder> token1 = sp<BBinder>::make();
+ sp<IBinder> token2 = sp<BBinder>::make();
tracker.insert(2, token1);
tracker.insert(5, token2);
@@ -104,8 +104,8 @@
TEST(AnrTrackerTest, MultipleTokens_IdenticalTimes) {
AnrTracker tracker;
- sp<IBinder> token1 = new BBinder();
- sp<IBinder> token2 = new BBinder();
+ sp<IBinder> token1 = sp<BBinder>::make();
+ sp<IBinder> token2 = sp<BBinder>::make();
tracker.insert(2, token1);
tracker.insert(2, token2);
@@ -119,8 +119,8 @@
TEST(AnrTrackerTest, MultipleTokens_IdenticalTimesRemove) {
AnrTracker tracker;
- sp<IBinder> token1 = new BBinder();
- sp<IBinder> token2 = new BBinder();
+ sp<IBinder> token1 = sp<BBinder>::make();
+ sp<IBinder> token2 = sp<BBinder>::make();
tracker.insert(2, token1);
tracker.insert(2, token2);
@@ -152,12 +152,12 @@
ASSERT_EQ(nullptr, tracker.firstToken());
// Remove with non-matching token
- tracker.erase(1, new BBinder());
+ tracker.erase(1, sp<BBinder>::make());
ASSERT_EQ(1, tracker.firstTimeout());
ASSERT_EQ(nullptr, tracker.firstToken());
// Remove with both non-matching
- tracker.erase(2, new BBinder());
+ tracker.erase(2, sp<BBinder>::make());
ASSERT_EQ(1, tracker.firstTimeout());
ASSERT_EQ(nullptr, tracker.firstToken());
}
diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp
index ef68a84..6ef6e44 100644
--- a/services/inputflinger/tests/EventHub_test.cpp
+++ b/services/inputflinger/tests/EventHub_test.cpp
@@ -180,6 +180,20 @@
}
/**
+ * Ensure that two identical devices get assigned unique descriptors from EventHub.
+ */
+TEST_F(EventHubTest, DevicesWithMatchingUniqueIdsAreUnique) {
+ std::unique_ptr<UinputHomeKey> keyboard2 = createUinputDevice<UinputHomeKey>();
+ int32_t deviceId2;
+ ASSERT_NO_FATAL_FAILURE(deviceId2 = waitForDeviceCreation());
+
+ ASSERT_NE(mEventHub->getDeviceIdentifier(mDeviceId).descriptor,
+ mEventHub->getDeviceIdentifier(deviceId2).descriptor);
+ keyboard2.reset();
+ waitForDeviceClose(deviceId2);
+}
+
+/**
* Ensure that input_events are generated with monotonic clock.
* That means input_event should receive a timestamp that is in the future of the time
* before the event was sent.
diff --git a/services/inputflinger/tests/FocusResolver_test.cpp b/services/inputflinger/tests/FocusResolver_test.cpp
index 91be4a3..5d5cf9c 100644
--- a/services/inputflinger/tests/FocusResolver_test.cpp
+++ b/services/inputflinger/tests/FocusResolver_test.cpp
@@ -50,16 +50,16 @@
};
TEST(FocusResolverTest, SetFocusedWindow) {
- sp<IBinder> focusableWindowToken = new BBinder();
- sp<IBinder> invisibleWindowToken = new BBinder();
- sp<IBinder> unfocusableWindowToken = new BBinder();
+ sp<IBinder> focusableWindowToken = sp<BBinder>::make();
+ sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
+ sp<IBinder> unfocusableWindowToken = sp<BBinder>::make();
std::vector<sp<WindowInfoHandle>> windows;
- windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */,
- true /* visible */));
- windows.push_back(new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
- false /* visible */));
- windows.push_back(new FakeWindowHandle("unfocusable", unfocusableWindowToken,
- false /* focusable */, true /* visible */));
+ windows.push_back(sp<FakeWindowHandle>::make("Focusable", focusableWindowToken,
+ true /* focusable */, true /* visible */));
+ windows.push_back(sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken,
+ true /* focusable */, false /* visible */));
+ windows.push_back(sp<FakeWindowHandle>::make("unfocusable", unfocusableWindowToken,
+ false /* focusable */, true /* visible */));
// focusable window can get focused
FocusRequest request;
@@ -85,10 +85,10 @@
}
TEST(FocusResolverTest, RemoveFocusFromFocusedWindow) {
- sp<IBinder> focusableWindowToken = new BBinder();
+ sp<IBinder> focusableWindowToken = sp<BBinder>::make();
std::vector<sp<WindowInfoHandle>> windows;
- windows.push_back(new FakeWindowHandle("Focusable", focusableWindowToken, true /* focusable */,
- true /* visible */));
+ windows.push_back(sp<FakeWindowHandle>::make("Focusable", focusableWindowToken,
+ true /* focusable */, true /* visible */));
FocusRequest request;
request.displayId = 42;
@@ -109,24 +109,24 @@
}
TEST(FocusResolverTest, SetFocusedMirroredWindow) {
- sp<IBinder> focusableWindowToken = new BBinder();
- sp<IBinder> invisibleWindowToken = new BBinder();
- sp<IBinder> unfocusableWindowToken = new BBinder();
+ sp<IBinder> focusableWindowToken = sp<BBinder>::make();
+ sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
+ sp<IBinder> unfocusableWindowToken = sp<BBinder>::make();
std::vector<sp<WindowInfoHandle>> windows;
- windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
- true /* visible */));
- windows.push_back(new FakeWindowHandle("Mirror1", focusableWindowToken, true /* focusable */,
- true /* visible */));
+ windows.push_back(sp<FakeWindowHandle>::make("Mirror1", focusableWindowToken,
+ true /* focusable */, true /* visible */));
+ windows.push_back(sp<FakeWindowHandle>::make("Mirror1", focusableWindowToken,
+ true /* focusable */, true /* visible */));
- windows.push_back(new FakeWindowHandle("Mirror2Visible", invisibleWindowToken,
- true /* focusable */, true /* visible */));
- windows.push_back(new FakeWindowHandle("Mirror2Invisible", invisibleWindowToken,
- true /* focusable */, false /* visible */));
+ windows.push_back(sp<FakeWindowHandle>::make("Mirror2Visible", invisibleWindowToken,
+ true /* focusable */, true /* visible */));
+ windows.push_back(sp<FakeWindowHandle>::make("Mirror2Invisible", invisibleWindowToken,
+ true /* focusable */, false /* visible */));
- windows.push_back(new FakeWindowHandle("Mirror3Focusable", unfocusableWindowToken,
- true /* focusable */, true /* visible */));
- windows.push_back(new FakeWindowHandle("Mirror3Unfocusable", unfocusableWindowToken,
- false /* focusable */, true /* visible */));
+ windows.push_back(sp<FakeWindowHandle>::make("Mirror3Focusable", unfocusableWindowToken,
+ true /* focusable */, true /* visible */));
+ windows.push_back(sp<FakeWindowHandle>::make("Mirror3Unfocusable", unfocusableWindowToken,
+ false /* focusable */, true /* visible */));
// mirrored window can get focused
FocusRequest request;
@@ -149,10 +149,11 @@
}
TEST(FocusResolverTest, SetInputWindows) {
- sp<IBinder> focusableWindowToken = new BBinder();
+ sp<IBinder> focusableWindowToken = sp<BBinder>::make();
std::vector<sp<WindowInfoHandle>> windows;
- sp<FakeWindowHandle> window = new FakeWindowHandle("Focusable", focusableWindowToken,
- true /* focusable */, true /* visible */);
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make("Focusable", focusableWindowToken, true /* focusable */,
+ true /* visible */);
windows.push_back(window);
// focusable window can get focused
@@ -171,12 +172,12 @@
}
TEST(FocusResolverTest, FocusRequestsCanBePending) {
- sp<IBinder> invisibleWindowToken = new BBinder();
+ sp<IBinder> invisibleWindowToken = sp<BBinder>::make();
std::vector<sp<WindowInfoHandle>> windows;
sp<FakeWindowHandle> invisibleWindow =
- new FakeWindowHandle("Invisible", invisibleWindowToken, true /* focusable */,
- false /* visible */);
+ sp<FakeWindowHandle>::make("Invisible", invisibleWindowToken, true /* focusable */,
+ false /* visible */);
windows.push_back(invisibleWindow);
// invisible window cannot get focused
@@ -195,11 +196,12 @@
}
TEST(FocusResolverTest, FocusRequestsArePersistent) {
- sp<IBinder> windowToken = new BBinder();
+ sp<IBinder> windowToken = sp<BBinder>::make();
std::vector<sp<WindowInfoHandle>> windows;
- sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
- false /* focusable */, true /* visible */);
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make("Test Window", windowToken, false /* focusable */,
+ true /* visible */);
windows.push_back(window);
// non-focusable window cannot get focused
@@ -236,17 +238,17 @@
}
TEST(FocusResolverTest, ConditionalFocusRequestsAreNotPersistent) {
- sp<IBinder> hostWindowToken = new BBinder();
+ sp<IBinder> hostWindowToken = sp<BBinder>::make();
std::vector<sp<WindowInfoHandle>> windows;
sp<FakeWindowHandle> hostWindow =
- new FakeWindowHandle("Host Window", hostWindowToken, true /* focusable */,
- true /* visible */);
+ sp<FakeWindowHandle>::make("Host Window", hostWindowToken, true /* focusable */,
+ true /* visible */);
windows.push_back(hostWindow);
- sp<IBinder> embeddedWindowToken = new BBinder();
+ sp<IBinder> embeddedWindowToken = sp<BBinder>::make();
sp<FakeWindowHandle> embeddedWindow =
- new FakeWindowHandle("Embedded Window", embeddedWindowToken, true /* focusable */,
- true /* visible */);
+ sp<FakeWindowHandle>::make("Embedded Window", embeddedWindowToken, true /* focusable */,
+ true /* visible */);
windows.push_back(embeddedWindow);
FocusRequest request;
@@ -287,11 +289,12 @@
ASSERT_FALSE(changes);
}
TEST(FocusResolverTest, FocusRequestsAreClearedWhenWindowIsRemoved) {
- sp<IBinder> windowToken = new BBinder();
+ sp<IBinder> windowToken = sp<BBinder>::make();
std::vector<sp<WindowInfoHandle>> windows;
- sp<FakeWindowHandle> window = new FakeWindowHandle("Test Window", windowToken,
- true /* focusable */, true /* visible */);
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make("Test Window", windowToken, true /* focusable */,
+ true /* visible */);
windows.push_back(window);
FocusRequest request;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 8a2dea5..cd853a6 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -515,7 +515,7 @@
std::unique_ptr<InputDispatcher> mDispatcher;
void SetUp() override {
- mFakePolicy = new FakeInputDispatcherPolicy();
+ mFakePolicy = sp<FakeInputDispatcherPolicy>::make();
mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy, STALE_EVENT_TIMEOUT);
mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
// Start InputDispatcher thread
@@ -752,7 +752,7 @@
public:
FakeApplicationHandle() {
mInfo.name = "Fake Application";
- mInfo.token = new BBinder();
+ mInfo.token = sp<BBinder>::make();
mInfo.dispatchingTimeoutMillis =
std::chrono::duration_cast<std::chrono::milliseconds>(DISPATCHING_TIMEOUT).count();
}
@@ -1028,8 +1028,8 @@
const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
const std::unique_ptr<InputDispatcher>& dispatcher, int32_t displayId) {
sp<FakeWindowHandle> handle =
- new FakeWindowHandle(inputApplicationHandle, dispatcher, mInfo.name + "(Mirror)",
- displayId, mInfo.token);
+ sp<FakeWindowHandle>::make(inputApplicationHandle, dispatcher,
+ mInfo.name + "(Mirror)", displayId, mInfo.token);
return handle;
}
@@ -1563,8 +1563,8 @@
TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Window that breaks its input channel",
- ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Window that breaks its input channel", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -1575,8 +1575,8 @@
TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1589,8 +1589,8 @@
TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
// Inject a MotionEvent to an unknown display.
@@ -1609,8 +1609,8 @@
*/
TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 100, 100));
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -1628,8 +1628,8 @@
*/
TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 100, 100));
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -1647,9 +1647,9 @@
TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> windowTop =
- new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
sp<FakeWindowHandle> windowSecond =
- new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1671,10 +1671,10 @@
TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCanceled) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> foregroundWindow =
- new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
foregroundWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> wallpaperWindow =
- new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setIsWallpaper(true);
constexpr int expectedWallpaperFlags =
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1715,10 +1715,10 @@
TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> foregroundWindow =
- new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
foregroundWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> wallpaperWindow =
- new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setIsWallpaper(true);
constexpr int expectedWallpaperFlags =
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1759,11 +1759,11 @@
TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
window->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> wallpaperWindow =
- new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setIsWallpaper(true);
constexpr int expectedWallpaperFlags =
AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
@@ -1814,17 +1814,17 @@
TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> leftWindow =
- new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
leftWindow->setFrame(Rect(0, 0, 200, 200));
leftWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> rightWindow =
- new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
rightWindow->setFrame(Rect(200, 0, 400, 200));
rightWindow->setDupTouchToWallpaper(true);
sp<FakeWindowHandle> wallpaperWindow =
- new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
wallpaperWindow->setIsWallpaper(true);
constexpr int expectedWallpaperFlags =
@@ -1901,7 +1901,7 @@
TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Window", DISPLAY_ID);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", DISPLAY_ID);
mDispatcher->setInputWindows({{DISPLAY_ID, {window}}});
NotifyMotionArgs args;
@@ -1925,11 +1925,11 @@
TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window1 =
- new FakeWindowHandle(application, mDispatcher, "Window1", DISPLAY_ID);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
window1->setTouchableRegion(Region{{0, 0, 100, 100}});
window1->setTouchable(false);
sp<FakeWindowHandle> window2 =
- new FakeWindowHandle(application, mDispatcher, "Window2", DISPLAY_ID);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
window2->setTouchableRegion(Region{{100, 0, 200, 100}});
mDispatcher->setInputWindows({{DISPLAY_ID, {window1, window2}}});
@@ -1955,10 +1955,10 @@
TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window1 =
- new FakeWindowHandle(application, mDispatcher, "Window1", DISPLAY_ID);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window1", DISPLAY_ID);
window1->setTouchableRegion(Region{{0, 0, 100, 100}});
sp<FakeWindowHandle> window2 =
- new FakeWindowHandle(application, mDispatcher, "Window2", DISPLAY_ID);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window2", DISPLAY_ID);
window2->setTouchableRegion(Region{{100, 0, 200, 100}});
mDispatcher->setInputWindows({{DISPLAY_ID, {window1, window2}}});
@@ -2022,10 +2022,10 @@
TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> windowLeft =
- new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
windowLeft->setFrame(Rect(0, 0, 600, 800));
sp<FakeWindowHandle> windowRight =
- new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
windowRight->setFrame(Rect(600, 0, 1200, 800));
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -2131,7 +2131,7 @@
TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 1200, 800));
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -2212,10 +2212,10 @@
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> windowLeft =
- new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
windowLeft->setFrame(Rect(0, 0, 600, 800));
sp<FakeWindowHandle> windowRight =
- new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
windowRight->setFrame(Rect(600, 0, 1200, 800));
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -2233,8 +2233,8 @@
TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -2258,8 +2258,8 @@
TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -2281,8 +2281,8 @@
TEST_F(InputDispatcherTest, InterceptKeyByPolicy) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -2303,8 +2303,8 @@
TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -2331,15 +2331,17 @@
TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) {
// There are three windows that do not overlap. `window` wants to WATCH_OUTSIDE_TOUCH.
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "First Window", ADISPLAY_ID_DEFAULT);
window->setWatchOutsideTouch(true);
window->setFrame(Rect{0, 0, 100, 100});
sp<FakeWindowHandle> secondWindow =
- new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+ ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect{100, 100, 200, 200});
sp<FakeWindowHandle> thirdWindow =
- new FakeWindowHandle(application, mDispatcher, "Third Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Third Window",
+ ADISPLAY_ID_DEFAULT);
thirdWindow->setFrame(Rect{200, 200, 300, 300});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, secondWindow, thirdWindow}}});
@@ -2370,6 +2372,35 @@
thirdWindow->consumeMotionDown();
}
+TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
+ window->setFocusable(true);
+
+ mDispatcher->onWindowInfosChanged({*window->getInfo()}, {});
+ setFocusedWindow(window);
+
+ window->consumeFocusEvent(true);
+
+ NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+ NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyKey(&keyDown);
+ mDispatcher->notifyKey(&keyUp);
+
+ window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
+ window->consumeKeyUp(ADISPLAY_ID_DEFAULT);
+
+ // All windows are removed from the display. Ensure that we can no longer dispatch to it.
+ mDispatcher->onWindowInfosChanged({}, {});
+
+ window->consumeFocusEvent(false);
+
+ mDispatcher->notifyKey(&keyDown);
+ mDispatcher->notifyKey(&keyUp);
+ window->assertNoEvents();
+}
+
/**
* Ensure the correct coordinate spaces are used by InputDispatcher.
*
@@ -2412,13 +2443,14 @@
// Add two windows to the display. Their frames are represented in the display space.
sp<FakeWindowHandle> firstWindow =
- new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+ ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
addWindow(firstWindow);
sp<FakeWindowHandle> secondWindow =
- new FakeWindowHandle(application, mDispatcher, "Second Window",
- ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+ ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
addWindow(secondWindow);
return {std::move(firstWindow), std::move(secondWindow)};
@@ -2519,9 +2551,11 @@
// Create a couple of windows
sp<FakeWindowHandle> firstWindow =
- new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+ ADISPLAY_ID_DEFAULT);
sp<FakeWindowHandle> secondWindow =
- new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+ ADISPLAY_ID_DEFAULT);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
@@ -2570,13 +2604,13 @@
// Create a couple of windows + a spy window
sp<FakeWindowHandle> spyWindow =
- new FakeWindowHandle(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
spyWindow->setTrustedOverlay(true);
spyWindow->setSpy(true);
sp<FakeWindowHandle> firstWindow =
- new FakeWindowHandle(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "First", ADISPLAY_ID_DEFAULT);
sp<FakeWindowHandle> secondWindow =
- new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
// Add the windows to the dispatcher
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, firstWindow, secondWindow}}});
@@ -2617,10 +2651,12 @@
// Create a couple of windows
sp<FakeWindowHandle> firstWindow =
- new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+ ADISPLAY_ID_DEFAULT);
firstWindow->setPreventSplitting(true);
sp<FakeWindowHandle> secondWindow =
- new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+ ADISPLAY_ID_DEFAULT);
secondWindow->setPreventSplitting(true);
// Add the windows to the dispatcher
@@ -2692,11 +2728,13 @@
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> firstWindow =
- new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+ ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 600, 400));
sp<FakeWindowHandle> secondWindow =
- new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+ ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(0, 400, 600, 800));
// Add the windows to the dispatcher
@@ -2756,11 +2794,13 @@
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> firstWindow =
- new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+ ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 600, 400));
sp<FakeWindowHandle> secondWindow =
- new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+ ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(0, 400, 600, 800));
// Add the windows to the dispatcher
@@ -2821,10 +2861,10 @@
TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> firstWindowInPrimary =
- new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
sp<FakeWindowHandle> secondWindowInPrimary =
- new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
sp<FakeWindowHandle> mirrorWindowInPrimary =
@@ -2880,10 +2920,10 @@
TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> firstWindowInPrimary =
- new FakeWindowHandle(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W1", ADISPLAY_ID_DEFAULT);
firstWindowInPrimary->setFrame(Rect(0, 0, 100, 100));
sp<FakeWindowHandle> secondWindowInPrimary =
- new FakeWindowHandle(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100));
sp<FakeWindowHandle> mirrorWindowInPrimary =
@@ -2935,8 +2975,8 @@
TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -2953,8 +2993,8 @@
TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -2968,8 +3008,8 @@
// If a window is touchable, but does not have focus, it should receive motion events, but not keys
TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -2991,11 +3031,13 @@
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> firstWindow =
- new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+ ADISPLAY_ID_DEFAULT);
firstWindow->setFrame(Rect(0, 0, 600, 400));
sp<FakeWindowHandle> secondWindow =
- new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+ ADISPLAY_ID_DEFAULT);
secondWindow->setFrame(Rect(0, 400, 600, 800));
// Add the windows to the dispatcher
@@ -3046,7 +3088,7 @@
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
@@ -3136,7 +3178,7 @@
TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDisappears) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
@@ -3176,8 +3218,8 @@
TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
@@ -3193,8 +3235,8 @@
FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -3218,8 +3260,8 @@
TEST_F(InputDispatcherMonitorTest, NoWindowTransform) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
window->setWindowOffset(20, 40);
window->setWindowTransform(0, 1, -1, 0);
@@ -3247,8 +3289,8 @@
TEST_F(InputDispatcherTest, TestMoveEvent) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Fake Window", ADISPLAY_ID_DEFAULT);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -3278,8 +3320,8 @@
*/
TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Test window", ADISPLAY_ID_DEFAULT);
const WindowInfo& windowInfo = *window->getInfo();
// Set focused application.
@@ -3324,8 +3366,8 @@
TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Test window", ADISPLAY_ID_DEFAULT);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
window->setFocusable(true);
@@ -3363,8 +3405,8 @@
TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Test window", ADISPLAY_ID_DEFAULT);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -3468,9 +3510,9 @@
TEST_F(InputDispatcherTest, SetFocusedWindow) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> windowTop =
- new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
sp<FakeWindowHandle> windowSecond =
- new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
// Top window is also focusable but is not granted focus.
@@ -3491,7 +3533,7 @@
TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
window->setFocusable(true);
@@ -3511,7 +3553,7 @@
TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
window->setFocusable(false);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -3529,9 +3571,9 @@
TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> windowTop =
- new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
sp<FakeWindowHandle> windowSecond =
- new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
windowTop->setFocusable(true);
@@ -3554,9 +3596,9 @@
TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestFocusTokenNotFocused) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> windowTop =
- new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
sp<FakeWindowHandle> windowSecond =
- new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
windowTop->setFocusable(true);
@@ -3575,10 +3617,10 @@
TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
sp<FakeWindowHandle> previousFocusedWindow =
- new FakeWindowHandle(application, mDispatcher, "previousFocusedWindow",
- ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "previousFocusedWindow",
+ ADISPLAY_ID_DEFAULT);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
window->setFocusable(true);
@@ -3613,7 +3655,7 @@
TEST_F(InputDispatcherTest, DisplayRemoved) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "window", ADISPLAY_ID_DEFAULT);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
// window is granted focus.
@@ -3658,7 +3700,7 @@
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
sp<FakeWindowHandle> slipperyExitWindow =
- new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
slipperyExitWindow->setSlippery(true);
// Make sure this one overlaps the bottom window
slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
@@ -3667,7 +3709,7 @@
slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
sp<FakeWindowHandle> slipperyEnterWindow =
- new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
mDispatcher->setInputWindows(
@@ -3701,7 +3743,7 @@
sp<FakeWindowHandle> mWindow;
virtual void SetUp() override {
- mFakePolicy = new FakeInputDispatcherPolicy();
+ mFakePolicy = sp<FakeInputDispatcherPolicy>::make();
mFakePolicy->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY);
mDispatcher = std::make_unique<InputDispatcher>(mFakePolicy);
mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
@@ -3712,7 +3754,7 @@
void setUpWindow() {
mApp = std::make_shared<FakeApplicationHandle>();
- mWindow = new FakeWindowHandle(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
mWindow->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
@@ -3849,7 +3891,7 @@
application1 = std::make_shared<FakeApplicationHandle>();
windowInPrimary =
- new FakeWindowHandle(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
// Set focus window for primary display, but focused display would be second one.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
@@ -3860,7 +3902,7 @@
application2 = std::make_shared<FakeApplicationHandle>();
windowInSecondary =
- new FakeWindowHandle(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
+ sp<FakeWindowHandle>::make(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
// Set focus to second display window.
// Set focus display to second one.
mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
@@ -3989,7 +4031,7 @@
TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) {
sp<FakeWindowHandle> secondWindowInPrimary =
- new FakeWindowHandle(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT);
secondWindowInPrimary->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowInPrimary, secondWindowInPrimary}}});
setFocusedWindow(secondWindowInPrimary);
@@ -4158,8 +4200,8 @@
std::shared_ptr<InputApplicationHandle> application =
std::make_shared<FakeApplicationHandle>();
- mWindow =
- new FakeWindowHandle(application, mDispatcher, "Test Window", ADISPLAY_ID_DEFAULT);
+ mWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Test Window",
+ ADISPLAY_ID_DEFAULT);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
mWindow->setFocusable(true);
@@ -4263,11 +4305,11 @@
std::shared_ptr<FakeApplicationHandle> application =
std::make_shared<FakeApplicationHandle>();
mUnfocusedWindow =
- new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
mFocusedWindow =
- new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
// Set focused application.
@@ -4373,12 +4415,12 @@
std::shared_ptr<FakeApplicationHandle> application =
std::make_shared<FakeApplicationHandle>();
- mWindow1 = new FakeWindowHandle(application, mDispatcher, "Fake Window 1",
- ADISPLAY_ID_DEFAULT);
+ mWindow1 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 1",
+ ADISPLAY_ID_DEFAULT);
mWindow1->setFrame(Rect(0, 0, 100, 100));
- mWindow2 = new FakeWindowHandle(application, mDispatcher, "Fake Window 2",
- ADISPLAY_ID_DEFAULT, mWindow1->getToken());
+ mWindow2 = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window 2",
+ ADISPLAY_ID_DEFAULT, mWindow1->getToken());
mWindow2->setFrame(Rect(100, 100, 200, 200));
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}});
@@ -4560,8 +4602,8 @@
mApplication = std::make_shared<FakeApplicationHandle>();
mApplication->setDispatchingTimeout(20ms);
- mWindow =
- new FakeWindowHandle(mApplication, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ mWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "TestWindow",
+ ADISPLAY_ID_DEFAULT);
mWindow->setFrame(Rect(0, 0, 30, 30));
mWindow->setDispatchingTimeout(30ms);
mWindow->setFocusable(true);
@@ -4595,7 +4637,7 @@
sp<FakeWindowHandle> addSpyWindow() {
sp<FakeWindowHandle> spy =
- new FakeWindowHandle(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
spy->setTrustedOverlay(true);
spy->setFocusable(false);
spy->setSpy(true);
@@ -4676,6 +4718,36 @@
// We have a focused application, but no focused window
TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) {
+ FocusRequest request;
+ request.token = nullptr;
+ request.windowName = "";
+ request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ request.displayId = mWindow->getInfo()->displayId;
+ mDispatcher->setFocusedWindow(request);
+ mWindow->consumeFocusEvent(false);
+
+ // taps on the window work as normal
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ WINDOW_LOCATION));
+ ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
+ mDispatcher->waitForIdle();
+ mFakePolicy->assertNotifyAnrWasNotCalled();
+
+ // Once a focused event arrives, we get an ANR for this application
+ // We specify the injection timeout to be smaller than the application timeout, to ensure that
+ // injection times out (instead of failing).
+ const InputEventInjectionResult result =
+ injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT,
+ InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
+ ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
+ const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
+ mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
+ ASSERT_TRUE(mDispatcher->waitForIdle());
+}
+
+// We have a focused application, but we are waiting on the requested window to become focusable
+TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_PendingFocusedRequest) {
mWindow->setFocusable(false);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}});
mWindow->consumeFocusEvent(false);
@@ -4696,7 +4768,7 @@
InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
ASSERT_TRUE(mDispatcher->waitForIdle());
}
@@ -4746,11 +4818,10 @@
injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /* repeatCount */, ADISPLAY_ID_DEFAULT,
InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, false /* allowKeyRepeat */);
ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
- const std::chrono::duration appTimeout =
- mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(appTimeout, mApplication);
+ const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
- std::this_thread::sleep_for(appTimeout);
+ std::this_thread::sleep_for(timeout);
// ANR should not be raised again. It is up to policy to do that if it desires.
mFakePolicy->assertNotifyAnrWasNotCalled();
@@ -4771,8 +4842,8 @@
InputEventInjectionSync::WAIT_FOR_RESULT, 10ms);
ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result);
- const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT);
- mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication);
+ const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT);
+ mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mWindow);
// Future focused events get dropped right away
ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(mDispatcher));
@@ -5041,14 +5112,14 @@
mApplication = std::make_shared<FakeApplicationHandle>();
mApplication->setDispatchingTimeout(10ms);
- mUnfocusedWindow =
- new FakeWindowHandle(mApplication, mDispatcher, "Unfocused", ADISPLAY_ID_DEFAULT);
+ mUnfocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Unfocused",
+ ADISPLAY_ID_DEFAULT);
mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
// Adding FLAG_WATCH_OUTSIDE_TOUCH to receive ACTION_OUTSIDE when another window is tapped
mUnfocusedWindow->setWatchOutsideTouch(true);
- mFocusedWindow =
- new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT);
+ mFocusedWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Focused",
+ ADISPLAY_ID_DEFAULT);
mFocusedWindow->setDispatchingTimeout(30ms);
mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
@@ -5415,16 +5486,17 @@
InputDispatcherTest::SetUp();
mApplication = std::make_shared<FakeApplicationHandle>();
- mNoInputWindow = new FakeWindowHandle(mApplication, mDispatcher,
- "Window without input channel", ADISPLAY_ID_DEFAULT,
- std::make_optional<sp<IBinder>>(nullptr) /*token*/);
+ mNoInputWindow =
+ sp<FakeWindowHandle>::make(mApplication, mDispatcher,
+ "Window without input channel", ADISPLAY_ID_DEFAULT,
+ std::make_optional<sp<IBinder>>(nullptr) /*token*/);
mNoInputWindow->setNoInputChannel(true);
mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
// It's perfectly valid for this window to not have an associated input channel
- mBottomWindow = new FakeWindowHandle(mApplication, mDispatcher, "Bottom window",
- ADISPLAY_ID_DEFAULT);
+ mBottomWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher, "Bottom window",
+ ADISPLAY_ID_DEFAULT);
mBottomWindow->setFrame(Rect(0, 0, 100, 100));
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mNoInputWindow, mBottomWindow}}});
@@ -5457,9 +5529,9 @@
*/
TEST_F(InputDispatcherMultiWindowOcclusionTests,
NoInputChannelFeature_DropsTouchesWithValidChannel) {
- mNoInputWindow = new FakeWindowHandle(mApplication, mDispatcher,
- "Window with input channel and NO_INPUT_CHANNEL",
- ADISPLAY_ID_DEFAULT);
+ mNoInputWindow = sp<FakeWindowHandle>::make(mApplication, mDispatcher,
+ "Window with input channel and NO_INPUT_CHANNEL",
+ ADISPLAY_ID_DEFAULT);
mNoInputWindow->setNoInputChannel(true);
mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
@@ -5485,9 +5557,9 @@
virtual void SetUp() override {
InputDispatcherTest::SetUp();
mApp = std::make_shared<FakeApplicationHandle>();
- mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
- mMirror = new FakeWindowHandle(mApp, mDispatcher, "TestWindowMirror", ADISPLAY_ID_DEFAULT,
- mWindow->getToken());
+ mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ mMirror = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindowMirror",
+ ADISPLAY_ID_DEFAULT, mWindow->getToken());
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
mWindow->setFocusable(true);
mMirror->setFocusable(true);
@@ -5629,9 +5701,10 @@
void SetUp() override {
InputDispatcherTest::SetUp();
mApp = std::make_shared<FakeApplicationHandle>();
- mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
mWindow->setFocusable(true);
- mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
+ mSecondWindow =
+ sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
mSecondWindow->setFocusable(true);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
@@ -5812,7 +5885,7 @@
sp<FakeWindowHandle> getWindow(int32_t uid, std::string name) {
std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
// Generate an arbitrary PID based on the UID
window->setOwnerInfo(1777 + (uid % 10000), uid);
return window;
@@ -6173,17 +6246,21 @@
sp<FakeWindowHandle> mSecondWindow;
sp<FakeWindowHandle> mDragWindow;
sp<FakeWindowHandle> mSpyWindow;
+ // Mouse would force no-split, set the id as non-zero to verify if drag state could track it.
+ static constexpr int32_t MOUSE_POINTER_ID = 1;
void SetUp() override {
InputDispatcherTest::SetUp();
mApp = std::make_shared<FakeApplicationHandle>();
- mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
mWindow->setFrame(Rect(0, 0, 100, 100));
- mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
+ mSecondWindow =
+ sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
mSecondWindow->setFrame(Rect(100, 0, 200, 100));
- mSpyWindow = new FakeWindowHandle(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT);
+ mSpyWindow =
+ sp<FakeWindowHandle>::make(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT);
mSpyWindow->setSpy(true);
mSpyWindow->setTrustedOverlay(true);
mSpyWindow->setFrame(Rect(0, 0, 200, 100));
@@ -6192,11 +6269,41 @@
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mSpyWindow, mWindow, mSecondWindow}}});
}
- void injectDown() {
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
- {50, 50}))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
+ switch (fromSource) {
+ case AINPUT_SOURCE_TOUCHSCREEN:
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ break;
+ case AINPUT_SOURCE_STYLUS:
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(
+ mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
+ AINPUT_SOURCE_STYLUS)
+ .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
+ .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS)
+ .x(50)
+ .y(50))
+ .build()));
+ break;
+ case AINPUT_SOURCE_MOUSE:
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(
+ mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID,
+ AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(50)
+ .y(50))
+ .build()));
+ break;
+ default:
+ FAIL() << "Source " << fromSource << " doesn't support drag and drop";
+ }
// Window should receive motion event.
mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
@@ -6207,13 +6314,14 @@
// Start performing drag, we will create a drag window and transfer touch to it.
// @param sendDown : if true, send a motion down on first window before perform drag and drop.
// Returns true on success.
- bool performDrag(bool sendDown = true) {
+ bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
if (sendDown) {
- injectDown();
+ injectDown(fromSource);
}
// The drag window covers the entire display
- mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
+ mDragWindow =
+ sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
mDispatcher->setInputWindows(
{{ADISPLAY_ID_DEFAULT, {mDragWindow, mSpyWindow, mWindow, mSecondWindow}}});
@@ -6228,36 +6336,10 @@
}
return transferred;
}
-
- // Start performing drag, we will create a drag window and transfer touch to it.
- void performStylusDrag() {
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionEvent(mDispatcher,
- MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
- AINPUT_SOURCE_STYLUS)
- .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY)
- .pointer(PointerBuilder(0,
- AMOTION_EVENT_TOOL_TYPE_STYLUS)
- .x(50)
- .y(50))
- .build()));
- mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
-
- // The drag window covers the entire display
- mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
- mDispatcher->setInputWindows(
- {{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}});
-
- // Transfer touch focus to the drag window
- mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
- true /* isDragDrop */);
- mWindow->consumeMotionCancel();
- mDragWindow->consumeMotionDown();
- }
};
TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) {
- performDrag();
+ startDrag();
// Move on window.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6295,7 +6377,7 @@
}
TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) {
- performDrag();
+ startDrag();
// No cancel event after drag start
mSpyWindow->assertNoEvents();
@@ -6319,7 +6401,7 @@
}
TEST_F(InputDispatcherDragTests, DragAndDrop) {
- performDrag();
+ startDrag();
// Move on window.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6351,7 +6433,7 @@
}
TEST_F(InputDispatcherDragTests, StylusDragAndDrop) {
- performStylusDrag();
+ startDrag(true, AINPUT_SOURCE_STYLUS);
// Move on window and keep button pressed.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -6398,7 +6480,7 @@
}
TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
- performDrag();
+ startDrag();
// Set second window invisible.
mSecondWindow->setVisible(false);
@@ -6434,6 +6516,9 @@
}
TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
+ // Ensure window could track pointerIds if it didn't support split touch.
+ mWindow->setPreventSplitting(true);
+
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
{50, 50}))
@@ -6454,7 +6539,7 @@
mWindow->consumeMotionPointerDown(1 /* pointerIndex */);
// Should not perform drag and drop when window has multi fingers.
- ASSERT_FALSE(performDrag(false));
+ ASSERT_FALSE(startDrag(false));
}
TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
@@ -6482,7 +6567,7 @@
mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
// Perform drag and drop from first window.
- ASSERT_TRUE(performDrag(false));
+ ASSERT_TRUE(startDrag(false));
// Move on window.
const MotionEvent secondFingerMoveEvent =
@@ -6517,11 +6602,11 @@
}
TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) {
- performDrag();
+ startDrag();
// Update window of second display.
sp<FakeWindowHandle> windowInSecondary =
- new FakeWindowHandle(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
+ sp<FakeWindowHandle>::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID);
mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}});
// Let second display has a touch state.
@@ -6568,12 +6653,61 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherDragTests, MouseDragAndDrop) {
+ startDrag(true, AINPUT_SOURCE_MOUSE);
+ // Move on window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID,
+ AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(50)
+ .y(50))
+ .build()))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(false, 50, 50);
+ mSecondWindow->assertNoEvents();
+
+ // Move to another window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID,
+ AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(150)
+ .y(50))
+ .build()))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(true, 150, 50);
+ mSecondWindow->consumeDragEvent(false, 50, 50);
+
+ // drop to another window.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher,
+ MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
+ .buttonState(0)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID,
+ AMOTION_EVENT_TOOL_TYPE_MOUSE)
+ .x(150)
+ .y(50))
+ .build()))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ mFakePolicy->assertDropTargetEquals(mSecondWindow->getToken());
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+}
+
class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Test window", ADISPLAY_ID_DEFAULT);
window->setDropInput(true);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
window->setFocusable(true);
@@ -6611,14 +6745,14 @@
std::shared_ptr<FakeApplicationHandle> obscuringApplication =
std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> obscuringWindow =
- new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow",
- ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
+ ADISPLAY_ID_DEFAULT);
obscuringWindow->setFrame(Rect(0, 0, 50, 50));
obscuringWindow->setOwnerInfo(111, 111);
obscuringWindow->setTouchable(false);
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Test window", ADISPLAY_ID_DEFAULT);
window->setDropInputIfObscured(true);
window->setOwnerInfo(222, 222);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -6657,14 +6791,14 @@
std::shared_ptr<FakeApplicationHandle> obscuringApplication =
std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> obscuringWindow =
- new FakeWindowHandle(obscuringApplication, mDispatcher, "obscuringWindow",
- ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
+ ADISPLAY_ID_DEFAULT);
obscuringWindow->setFrame(Rect(0, 0, 50, 50));
obscuringWindow->setOwnerInfo(111, 111);
obscuringWindow->setTouchable(false);
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
+ "Test window", ADISPLAY_ID_DEFAULT);
window->setDropInputIfObscured(true);
window->setOwnerInfo(222, 222);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -6708,10 +6842,11 @@
InputDispatcherTest::SetUp();
mApp = std::make_shared<FakeApplicationHandle>();
- mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ mWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
mWindow->setFocusable(true);
setFocusedWindow(mWindow);
- mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
+ mSecondWindow =
+ sp<FakeWindowHandle>::make(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
mSecondWindow->setFocusable(true);
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
@@ -6794,8 +6929,8 @@
std::make_shared<FakeApplicationHandle>();
std::string name = "Fake Spy ";
name += std::to_string(mSpyCount++);
- sp<FakeWindowHandle> spy =
- new FakeWindowHandle(application, mDispatcher, name.c_str(), ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> spy = sp<FakeWindowHandle>::make(application, mDispatcher,
+ name.c_str(), ADISPLAY_ID_DEFAULT);
spy->setSpy(true);
spy->setTrustedOverlay(true);
return spy;
@@ -6805,7 +6940,8 @@
std::shared_ptr<FakeApplicationHandle> application =
std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window",
+ ADISPLAY_ID_DEFAULT);
window->setFocusable(true);
return window;
}
@@ -7383,8 +7519,8 @@
std::shared_ptr<FakeApplicationHandle> overlayApplication =
std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> overlay =
- new FakeWindowHandle(overlayApplication, mDispatcher, "Stylus interceptor window",
- ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
+ "Stylus interceptor window", ADISPLAY_ID_DEFAULT);
overlay->setFocusable(false);
overlay->setOwnerInfo(111, 111);
overlay->setTouchable(false);
@@ -7394,8 +7530,8 @@
std::shared_ptr<FakeApplicationHandle> application =
std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Application window",
- ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
+ ADISPLAY_ID_DEFAULT);
window->setFocusable(true);
window->setOwnerInfo(222, 222);
@@ -7535,8 +7671,9 @@
sp<FakeWindowHandle> createWindow() const {
std::shared_ptr<FakeApplicationHandle> overlayApplication =
std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window = new FakeWindowHandle(overlayApplication, mDispatcher,
- "Owned Window", ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(overlayApplication, mDispatcher, "Owned Window",
+ ADISPLAY_ID_DEFAULT);
window->setOwnerInfo(mPid, mUid);
return window;
}
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index 454e531..22ae894 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -223,8 +223,10 @@
if (forkPid == 0) {
// Server process
- android::sp<android::TestInputManager> manager = new android::TestInputManager();
- android::sp<android::TestInputQuery> query = new android::TestInputQuery(manager);
+ android::sp<android::TestInputManager> manager =
+ android::sp<android::TestInputManager>::make();
+ android::sp<android::TestInputQuery> query =
+ android::sp<android::TestInputQuery>::make(manager);
android::defaultServiceManager()->addService(android::kTestServiceName, manager,
false /*allowIsolated*/);
diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputProcessorConverter_test.cpp
similarity index 93%
rename from services/inputflinger/tests/InputClassifierConverter_test.cpp
rename to services/inputflinger/tests/InputProcessorConverter_test.cpp
index 81ef9b9..040c8da 100644
--- a/services/inputflinger/tests/InputClassifierConverter_test.cpp
+++ b/services/inputflinger/tests/InputProcessorConverter_test.cpp
@@ -24,7 +24,7 @@
namespace android {
-// --- InputClassifierConverterTest ---
+// --- InputProcessorConverterTest ---
static NotifyMotionArgs generateBasicMotionArgs() {
// Create a basic motion event for testing
@@ -52,7 +52,7 @@
static float getMotionEventAxis(common::PointerCoords coords, common::Axis axis) {
uint32_t index = BitSet64::getIndexOfBit(static_cast<uint64_t>(coords.bits),
- static_cast<uint64_t>(axis));
+ static_cast<uint64_t>(axis));
return coords.values[index];
}
@@ -60,7 +60,7 @@
* Check that coordinates get converted properly from the framework's PointerCoords
* to the hidl PointerCoords in input::common.
*/
-TEST(InputClassifierConverterTest, PointerCoordsAxes) {
+TEST(InputProcessorConverterTest, PointerCoordsAxes) {
const NotifyMotionArgs motionArgs = generateBasicMotionArgs();
ASSERT_EQ(1, motionArgs.pointerCoords[0].getX());
ASSERT_EQ(2, motionArgs.pointerCoords[0].getY());
@@ -76,7 +76,7 @@
ASSERT_EQ(getMotionEventAxis(motionEvent.pointerCoords[0], common::Axis::SIZE),
motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_SIZE));
ASSERT_EQ(BitSet64::count(motionArgs.pointerCoords[0].bits),
- BitSet64::count(motionEvent.pointerCoords[0].bits));
+ BitSet64::count(motionEvent.pointerCoords[0].bits));
}
} // namespace android
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputProcessor_test.cpp
similarity index 75%
rename from services/inputflinger/tests/InputClassifier_test.cpp
rename to services/inputflinger/tests/InputProcessor_test.cpp
index 3a77127..380001c 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputProcessor_test.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "../InputClassifier.h"
+#include "../InputProcessor.h"
#include <gtest/gtest.h>
#include <gui/constants.h>
@@ -31,7 +31,7 @@
namespace android {
-// --- InputClassifierTest ---
+// --- InputProcessorTest ---
static NotifyMotionArgs generateBasicMotionArgs() {
// Create a basic motion event for testing
@@ -56,105 +56,104 @@
return motionArgs;
}
-class InputClassifierTest : public testing::Test {
+class InputProcessorTest : public testing::Test {
protected:
TestInputListener mTestListener;
- std::unique_ptr<InputClassifierInterface> mClassifier;
+ std::unique_ptr<InputProcessorInterface> mProcessor;
- void SetUp() override { mClassifier = std::make_unique<InputClassifier>(mTestListener); }
+ void SetUp() override { mProcessor = std::make_unique<InputProcessor>(mTestListener); }
};
/**
- * Create a basic configuration change and send it to input classifier.
+ * Create a basic configuration change and send it to input processor.
* Expect that the event is received by the next input stage, unmodified.
*/
-TEST_F(InputClassifierTest, SendToNextStage_NotifyConfigurationChangedArgs) {
- // Create a basic configuration change and send to classifier
- NotifyConfigurationChangedArgs args(1/*sequenceNum*/, 2/*eventTime*/);
+TEST_F(InputProcessorTest, SendToNextStage_NotifyConfigurationChangedArgs) {
+ // Create a basic configuration change and send to processor
+ NotifyConfigurationChangedArgs args(1 /*sequenceNum*/, 2 /*eventTime*/);
- mClassifier->notifyConfigurationChanged(&args);
+ mProcessor->notifyConfigurationChanged(&args);
NotifyConfigurationChangedArgs outArgs;
ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyConfigurationChangedWasCalled(&outArgs));
ASSERT_EQ(args, outArgs);
}
-TEST_F(InputClassifierTest, SendToNextStage_NotifyKeyArgs) {
- // Create a basic key event and send to classifier
+TEST_F(InputProcessorTest, SendToNextStage_NotifyKeyArgs) {
+ // Create a basic key event and send to processor
NotifyKeyArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 21 /*readTime*/, 3 /*deviceId*/,
AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_DEFAULT, 0 /*policyFlags*/,
AKEY_EVENT_ACTION_DOWN, 4 /*flags*/, AKEYCODE_HOME, 5 /*scanCode*/,
AMETA_NONE, 6 /*downTime*/);
- mClassifier->notifyKey(&args);
+ mProcessor->notifyKey(&args);
NotifyKeyArgs outArgs;
ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyKeyWasCalled(&outArgs));
ASSERT_EQ(args, outArgs);
}
-
/**
- * Create a basic motion event and send it to input classifier.
+ * Create a basic motion event and send it to input processor.
* Expect that the event is received by the next input stage, unmodified.
*/
-TEST_F(InputClassifierTest, SendToNextStage_NotifyMotionArgs) {
+TEST_F(InputProcessorTest, SendToNextStage_NotifyMotionArgs) {
NotifyMotionArgs motionArgs = generateBasicMotionArgs();
- mClassifier->notifyMotion(&motionArgs);
+ mProcessor->notifyMotion(&motionArgs);
NotifyMotionArgs args;
ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyMotionWasCalled(&args));
ASSERT_EQ(motionArgs, args);
}
/**
- * Create a basic switch event and send it to input classifier.
+ * Create a basic switch event and send it to input processor.
* Expect that the event is received by the next input stage, unmodified.
*/
-TEST_F(InputClassifierTest, SendToNextStage_NotifySwitchArgs) {
- NotifySwitchArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*policyFlags*/, 4/*switchValues*/,
- 5/*switchMask*/);
+TEST_F(InputProcessorTest, SendToNextStage_NotifySwitchArgs) {
+ NotifySwitchArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 3 /*policyFlags*/, 4 /*switchValues*/,
+ 5 /*switchMask*/);
- mClassifier->notifySwitch(&args);
+ mProcessor->notifySwitch(&args);
NotifySwitchArgs outArgs;
ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifySwitchWasCalled(&outArgs));
ASSERT_EQ(args, outArgs);
}
/**
- * Create a basic device reset event and send it to input classifier.
+ * Create a basic device reset event and send it to input processor.
* Expect that the event is received by the next input stage, unmodified.
*/
-TEST_F(InputClassifierTest, SendToNextStage_NotifyDeviceResetArgs) {
- NotifyDeviceResetArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/);
+TEST_F(InputProcessorTest, SendToNextStage_NotifyDeviceResetArgs) {
+ NotifyDeviceResetArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 3 /*deviceId*/);
- mClassifier->notifyDeviceReset(&args);
+ mProcessor->notifyDeviceReset(&args);
NotifyDeviceResetArgs outArgs;
ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyDeviceResetWasCalled(&outArgs));
ASSERT_EQ(args, outArgs);
}
-TEST_F(InputClassifierTest, SetMotionClassifier_Enabled) {
- mClassifier->setMotionClassifierEnabled(true);
+TEST_F(InputProcessorTest, SetMotionClassifier_Enabled) {
+ mProcessor->setMotionClassifierEnabled(true);
}
-TEST_F(InputClassifierTest, SetMotionClassifier_Disabled) {
- mClassifier->setMotionClassifierEnabled(false);
+TEST_F(InputProcessorTest, SetMotionClassifier_Disabled) {
+ mProcessor->setMotionClassifierEnabled(false);
}
/**
* Try to break it by calling setMotionClassifierEnabled multiple times.
*/
-TEST_F(InputClassifierTest, SetMotionClassifier_Multiple) {
- mClassifier->setMotionClassifierEnabled(true);
- mClassifier->setMotionClassifierEnabled(true);
- mClassifier->setMotionClassifierEnabled(true);
- mClassifier->setMotionClassifierEnabled(false);
- mClassifier->setMotionClassifierEnabled(false);
- mClassifier->setMotionClassifierEnabled(true);
- mClassifier->setMotionClassifierEnabled(true);
- mClassifier->setMotionClassifierEnabled(true);
+TEST_F(InputProcessorTest, SetMotionClassifier_Multiple) {
+ mProcessor->setMotionClassifierEnabled(true);
+ mProcessor->setMotionClassifierEnabled(true);
+ mProcessor->setMotionClassifierEnabled(true);
+ mProcessor->setMotionClassifierEnabled(false);
+ mProcessor->setMotionClassifierEnabled(false);
+ mProcessor->setMotionClassifierEnabled(true);
+ mProcessor->setMotionClassifierEnabled(true);
+ mProcessor->setMotionClassifierEnabled(true);
}
/**
- * A minimal implementation of IInputClassifier.
+ * A minimal implementation of IInputProcessor.
*/
class TestHal : public aidl::android::hardware::input::processor::BnInputProcessor {
::ndk::ScopedAStatus classify(
@@ -212,7 +211,7 @@
NotifyMotionArgs motionArgs = generateBasicMotionArgs();
std::vector<int16_t> videoData = {1, 2, 3, 4};
- timeval timestamp = { 1, 1};
+ timeval timestamp = {1, 1};
TouchVideoFrame frame(2, 2, std::move(videoData), timestamp);
motionArgs.videoFrames = {frame};
@@ -228,11 +227,11 @@
NotifyMotionArgs motionArgs = generateBasicMotionArgs();
std::vector<int16_t> videoData1 = {1, 2, 3, 4};
- timeval timestamp1 = { 1, 1};
+ timeval timestamp1 = {1, 1};
TouchVideoFrame frame1(2, 2, std::move(videoData1), timestamp1);
std::vector<int16_t> videoData2 = {6, 6, 6, 6};
- timeval timestamp2 = { 1, 2};
+ timeval timestamp2 = {1, 2};
TouchVideoFrame frame2(2, 2, std::move(videoData2), timestamp2);
motionArgs.videoFrames = {frame1, frame2};
@@ -253,7 +252,7 @@
* Make sure MotionClassifier does not crash when a device is reset.
*/
TEST_F(MotionClassifierTest, DeviceReset_DoesNotCrash) {
- NotifyDeviceResetArgs args(1/*sequenceNum*/, 2/*eventTime*/, 3/*deviceId*/);
+ NotifyDeviceResetArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 3 /*deviceId*/);
ASSERT_NO_FATAL_FAILURE(mMotionClassifier->reset(args));
}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 67fcc40..a0e6192 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1332,7 +1332,7 @@
protected:
sp<FakeInputReaderPolicy> mFakePolicy;
- void SetUp() override { mFakePolicy = new FakeInputReaderPolicy(); }
+ void SetUp() override { mFakePolicy = sp<FakeInputReaderPolicy>::make(); }
void TearDown() override { mFakePolicy.clear(); }
};
@@ -1570,7 +1570,7 @@
void SetUp() override {
mFakeEventHub = std::make_unique<FakeEventHub>();
- mFakePolicy = new FakeInputReaderPolicy();
+ mFakePolicy = sp<FakeInputReaderPolicy>::make();
mFakeListener = std::make_unique<TestInputListener>();
mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
@@ -2254,7 +2254,7 @@
std::shared_ptr<FakePointerController> mFakePointerController;
void SetUp() override {
- mFakePolicy = new FakeInputReaderPolicy();
+ mFakePolicy = sp<FakeInputReaderPolicy>::make();
mFakePointerController = std::make_shared<FakePointerController>();
mFakePolicy->setPointerController(mFakePointerController);
mTestListener = std::make_unique<TestInputListener>(2000ms /*eventHappenedTimeout*/,
@@ -2653,7 +2653,7 @@
void SetUp() override {
mFakeEventHub = std::make_unique<FakeEventHub>();
- mFakePolicy = new FakeInputReaderPolicy();
+ mFakePolicy = sp<FakeInputReaderPolicy>::make();
mFakeListener = std::make_unique<TestInputListener>();
mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
*mFakeListener);
@@ -2940,11 +2940,13 @@
virtual void SetUp(ftl::Flags<InputDeviceClass> classes) {
mFakeEventHub = std::make_unique<FakeEventHub>();
- mFakePolicy = new FakeInputReaderPolicy();
+ mFakePolicy = sp<FakeInputReaderPolicy>::make();
mFakeListener = std::make_unique<TestInputListener>();
mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
*mFakeListener);
mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes);
+ // Consume the device reset notification generated when adding a new device.
+ mFakeListener->assertNotifyDeviceResetWasCalled();
}
void SetUp() override {
@@ -2969,6 +2971,8 @@
mReader->loopOnce();
}
mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
+ // Loop the reader to flush the input listener queue.
+ mReader->loopOnce();
}
std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
@@ -2992,6 +2996,8 @@
configureDevice(0);
mDevice->reset(ARBITRARY_TIME);
mapper.reset(ARBITRARY_TIME);
+ // Loop the reader to flush the input listener queue.
+ mReader->loopOnce();
return mapper;
}
@@ -3017,6 +3023,7 @@
event.code = code;
event.value = value;
mapper.process(&event);
+ // Loop the reader to flush the input listener queue.
mReader->loopOnce();
}
@@ -4913,7 +4920,6 @@
ASSERT_TRUE(mReader->getContext()->getGeneration() != generation);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
- ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
ASSERT_EQ(DEVICE_ID, resetArgs.deviceId);
process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10);
@@ -6696,6 +6702,89 @@
toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
}
+TEST_F(SingleTouchInputMapperTest,
+ Process_WhenViewportDisplayIdChanged_TouchIsCanceledAndDeviceIsReset) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
+ prepareAxes(POSITION);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+ NotifyMotionArgs motionArgs;
+
+ // Down.
+ processDown(mapper, 100, 200);
+ processSync(mapper);
+
+ // We should receive a down event
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+
+ // Change display id
+ clearViewports();
+ prepareSecondaryDisplay(ViewportType::INTERNAL);
+
+ // We should receive a cancel event
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+ // Then receive reset called
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
+}
+
+TEST_F(SingleTouchInputMapperTest,
+ Process_WhenViewportActiveStatusChanged_TouchIsCanceledAndDeviceIsReset) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ prepareButtons();
+ prepareAxes(POSITION);
+ SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
+ NotifyMotionArgs motionArgs;
+
+ // Start a new gesture.
+ processDown(mapper, 100, 200);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+
+ // Make the viewport inactive. This will put the device in disabled mode.
+ auto viewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
+ viewport->isActive = false;
+ mFakePolicy->updateViewport(*viewport);
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+ // We should receive a cancel event for the ongoing gesture.
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+ // Then we should be notified that the device was reset.
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
+
+ // No events are generated while the viewport is inactive.
+ processMove(mapper, 101, 201);
+ processSync(mapper);
+ processDown(mapper, 102, 202);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+ // Make the viewport active again. The device should resume processing events.
+ viewport->isActive = true;
+ mFakePolicy->updateViewport(*viewport);
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+ // The device is reset because it changes back to direct mode, without generating any events.
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+
+ // Start a new gesture.
+ processDown(mapper, 100, 200);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+
+ // No more events.
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasNotCalled());
+}
+
// --- TouchDisplayProjectionTest ---
class TouchDisplayProjectionTest : public SingleTouchInputMapperTest {
@@ -8553,27 +8642,27 @@
ASSERT_TRUE(mFakePolicy->updateViewport(displayViewport));
configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
- // Finger move
+ // The ongoing touch should be canceled immediately
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+
+ // Finger move is ignored
x += 10, y += 10;
processPosition(mapper, x, y);
processSync(mapper);
-
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
- EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
// Reactivate display viewport
displayViewport.isActive = true;
ASSERT_TRUE(mFakePolicy->updateViewport(displayViewport));
configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
- // Finger move again
+ // Finger move again starts new gesture
x += 10, y += 10;
processPosition(mapper, x, y);
processSync(mapper);
-
- // Gesture is aborted, so events after display is activated won't be dispatched until there is
- // no pointer on the touch device.
- mFakeListener->assertNotifyMotionWasNotCalled();
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
}
TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) {
@@ -8739,6 +8828,10 @@
// window's coordinate space.
frames[0].rotate(getInverseRotation(orientation));
ASSERT_EQ(frames, motionArgs.videoFrames);
+
+ // Release finger.
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
}
}
@@ -9801,7 +9894,7 @@
virtual void SetUp(ftl::Flags<InputDeviceClass> classes) {
mFakeEventHub = std::make_unique<FakeEventHub>();
- mFakePolicy = new FakeInputReaderPolicy();
+ mFakePolicy = sp<FakeInputReaderPolicy>::make();
mFakeListener = std::make_unique<TestInputListener>();
mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
*mFakeListener);
diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp
index 89c0741..1f4b248 100644
--- a/services/inputflinger/tests/LatencyTracker_test.cpp
+++ b/services/inputflinger/tests/LatencyTracker_test.cpp
@@ -44,7 +44,7 @@
graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 9;
graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 10;
expectedCT.setGraphicsTimeline(std::move(graphicsTimeline));
- t.connectionTimelines.emplace(new BBinder(), std::move(expectedCT));
+ t.connectionTimelines.emplace(sp<BBinder>::make(), std::move(expectedCT));
return t;
}
@@ -56,8 +56,8 @@
sp<IBinder> connection2;
void SetUp() override {
- connection1 = new BBinder();
- connection2 = new BBinder();
+ connection1 = sp<BBinder>::make();
+ connection2 = sp<BBinder>::make();
mTracker = std::make_unique<LatencyTracker>(this);
}
diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
index 8af3871..f2a3964 100644
--- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
+++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp
@@ -405,11 +405,11 @@
};
/**
- * Create a basic configuration change and send it to input classifier.
+ * Create a basic configuration change and send it to input processor.
* Expect that the event is received by the next input stage, unmodified.
*/
TEST_F(UnwantedInteractionBlockerTest, ConfigurationChangedIsPassedToNextListener) {
- // Create a basic configuration change and send to classifier
+ // Create a basic configuration change and send to blocker
NotifyConfigurationChangedArgs args(1 /*sequenceNum*/, 2 /*eventTime*/);
mBlocker->notifyConfigurationChanged(&args);
@@ -423,7 +423,7 @@
* to next stage unmodified.
*/
TEST_F(UnwantedInteractionBlockerTest, KeyIsPassedToNextListener) {
- // Create a basic key event and send to classifier
+ // Create a basic key event and send to blocker
NotifyKeyArgs args(1 /*sequenceNum*/, 2 /*eventTime*/, 21 /*readTime*/, 3 /*deviceId*/,
AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_DEFAULT, 0 /*policyFlags*/,
AKEY_EVENT_ACTION_DOWN, 4 /*flags*/, AKEYCODE_HOME, 5 /*scanCode*/,
diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
index 4f066ad..72780fb 100644
--- a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
@@ -42,7 +42,7 @@
if (useExistingToken) {
return tokens[fdp.ConsumeIntegralInRange<size_t>(0ul, tokens.size() - 1)];
}
- return new BBinder();
+ return sp<BBinder>::make();
}
extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
@@ -54,7 +54,7 @@
// Make some pre-defined tokens to ensure that some timelines are complete.
std::array<sp<IBinder> /*token*/, 10> predefinedTokens;
for (size_t i = 0; i < predefinedTokens.size(); i++) {
- predefinedTokens[i] = new BBinder();
+ predefinedTokens[i] = sp<BBinder>::make();
}
// Randomly invoke LatencyTracker api's until randomness is exhausted.
diff --git a/services/powermanager/tests/IThermalManagerTest.cpp b/services/powermanager/tests/IThermalManagerTest.cpp
index b62be5f..7414958 100644
--- a/services/powermanager/tests/IThermalManagerTest.cpp
+++ b/services/powermanager/tests/IThermalManagerTest.cpp
@@ -33,26 +33,38 @@
using namespace android::os;
using namespace std::chrono_literals;
-class IThermalServiceTest : public testing::Test,
- public BnThermalStatusListener{
+class IThermalServiceTestListener : public BnThermalStatusListener {
+ public:
+ virtual binder::Status onStatusChange(int status) override;
+ std::condition_variable mCondition;
+ int mListenerStatus = 0;
+ std::mutex mMutex;
+};
+
+binder::Status IThermalServiceTestListener::onStatusChange(int status) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mListenerStatus = status;
+ ALOGI("IThermalServiceTestListener::notifyListener %d", mListenerStatus);
+ mCondition.notify_all();
+ return binder::Status::ok();
+}
+
+class IThermalServiceTest : public testing::Test {
public:
IThermalServiceTest();
void setThermalOverride(int level);
- virtual binder::Status onStatusChange(int status) override;
int getStatusFromService();
void SetUp() override;
void TearDown() override;
protected:
sp<IThermalService> mThermalSvc;
- std::condition_variable mCondition;
- int mListenerStatus;
int mServiceStatus;
- std::mutex mMutex;
+ sp<IThermalServiceTestListener> mCallback;
};
IThermalServiceTest::IThermalServiceTest()
- : mListenerStatus(0),
- mServiceStatus(0) {
+ : mServiceStatus(0),
+ mCallback(sp<IThermalServiceTestListener>::make()) {
}
void IThermalServiceTest::setThermalOverride(int level) {
@@ -60,14 +72,6 @@
system(cmdStr.c_str());
}
-binder::Status IThermalServiceTest::onStatusChange(int status) {
- std::unique_lock<std::mutex> lock(mMutex);
- mListenerStatus = status;
- ALOGI("IThermalServiceTest::notifyListener %d", mListenerStatus);
- mCondition.notify_all();
- return binder::Status::ok();
-}
-
int IThermalServiceTest::getStatusFromService() {
int status;
binder::Status ret = mThermalSvc->getCurrentThermalStatus(&status);
@@ -87,19 +91,19 @@
mThermalSvc = interface_cast<IThermalService>(binder);
EXPECT_NE(mThermalSvc, nullptr);
// Lock mutex for operation, so listener will only be processed after wait_for is called
- std::unique_lock<std::mutex> lock(mMutex);
+ std::unique_lock<std::mutex> lock(mCallback->mMutex);
bool success = false;
- binder::Status ret = mThermalSvc->registerThermalStatusListener(this, &success);
+ binder::Status ret = mThermalSvc->registerThermalStatusListener(mCallback, &success);
// Check the result
ASSERT_TRUE(success);
ASSERT_TRUE(ret.isOk());
// Wait for listener called after registration, shouldn't timeout
- EXPECT_NE(mCondition.wait_for(lock, 1s), std::cv_status::timeout);
+ EXPECT_NE(mCallback->mCondition.wait_for(lock, 1s), std::cv_status::timeout);
}
void IThermalServiceTest::TearDown() {
bool success = false;
- binder::Status ret = mThermalSvc->unregisterThermalStatusListener(this, &success);
+ binder::Status ret = mThermalSvc->unregisterThermalStatusListener(mCallback, &success);
ASSERT_TRUE(success);
ASSERT_TRUE(ret.isOk());
}
@@ -114,14 +118,14 @@
TEST_P(IThermalListenerTest, TestListener) {
int level = GetParam();
// Lock mutex for operation, so listener will only be processed after wait_for is called
- std::unique_lock<std::mutex> lock(mMutex);
+ std::unique_lock<std::mutex> lock(mCallback->mMutex);
// Set the override thermal status
setThermalOverride(level);
// Wait for listener called, shouldn't timeout
- EXPECT_NE(mCondition.wait_for(lock, 1s), std::cv_status::timeout);
+ EXPECT_NE(mCallback->mCondition.wait_for(lock, 1s), std::cv_status::timeout);
// Check the result
- EXPECT_EQ(level, mListenerStatus);
- ALOGI("Thermal listener status %d, expecting %d", mListenerStatus, level);
+ EXPECT_EQ(level, mCallback->mListenerStatus);
+ ALOGI("Thermal listener status %d, expecting %d", mCallback->mListenerStatus, level);
}
INSTANTIATE_TEST_SUITE_P(TestListenerLevels, IThermalListenerTest, testing::Range(
@@ -158,4 +162,4 @@
ALOGV("Test result = %d\n", status);
return status;
-}
\ No newline at end of file
+}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index f1457bf..76429ff 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -18,6 +18,7 @@
"-Wunused",
"-Wunreachable-code",
"-Wconversion",
+ "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
}
@@ -145,7 +146,6 @@
"ClientCache.cpp",
"Client.cpp",
"EffectLayer.cpp",
- "ContainerLayer.cpp",
"DisplayDevice.cpp",
"DisplayHardware/AidlComposerHal.cpp",
"DisplayHardware/HidlComposerHal.cpp",
@@ -163,6 +163,7 @@
"FrameTracer/FrameTracer.cpp",
"FrameTracker.cpp",
"HdrLayerInfoReporter.cpp",
+ "HwcSlotGenerator.cpp",
"WindowInfosListenerInvoker.cpp",
"Layer.cpp",
"LayerProtoHelper.cpp",
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 59e2d18..51a5445 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -25,7 +25,6 @@
#include <FrameTimeline/FrameTimeline.h>
#include <compositionengine/CompositionEngine.h>
-#include <compositionengine/LayerFECompositionState.h>
#include <gui/BufferQueue.h>
#include <private/gui/SyncFeatures.h>
#include <renderengine/Image.h>
@@ -71,33 +70,74 @@
using PresentState = frametimeline::SurfaceFrame::PresentState;
using gui::WindowInfo;
-void BufferStateLayer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
- const sp<GraphicBuffer>& buffer,
- uint64_t framenumber,
- const sp<Fence>& releaseFence,
- uint32_t currentMaxAcquiredBufferCount) {
- if (!listener) {
- return;
- }
- ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber);
- listener->onReleaseBuffer({buffer->getId(), framenumber},
- releaseFence ? releaseFence : Fence::NO_FENCE,
- currentMaxAcquiredBufferCount);
-}
-
namespace {
static constexpr float defaultMaxLuminance = 1000.0;
+
+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);
+}
+
+bool assignTransform(ui::Transform* dst, ui::Transform& from) {
+ if (*dst == from) {
+ return false;
+ }
+ *dst = from;
+ return true;
+}
+
+TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) {
+ using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility;
+ using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness;
+ const auto frameRateCompatibility = [frameRate] {
+ switch (frameRate.type) {
+ case Layer::FrameRateCompatibility::Default:
+ return FrameRateCompatibility::Default;
+ case Layer::FrameRateCompatibility::ExactOrMultiple:
+ return FrameRateCompatibility::ExactOrMultiple;
+ default:
+ return FrameRateCompatibility::Undefined;
+ }
+ }();
+
+ const auto seamlessness = [frameRate] {
+ switch (frameRate.seamlessness) {
+ case scheduler::Seamlessness::OnlySeamless:
+ return Seamlessness::ShouldBeSeamless;
+ case scheduler::Seamlessness::SeamedAndSeamless:
+ return Seamlessness::NotRequired;
+ default:
+ return Seamlessness::Undefined;
+ }
+ }();
+
+ return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(),
+ .frameRateCompatibility = frameRateCompatibility,
+ .seamlessness = seamlessness};
+}
} // namespace
BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args)
: Layer(args),
mTextureName(args.textureName),
mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()},
- mHwcSlotGenerator(new HwcSlotGenerator()) {
+ mHwcSlotGenerator(sp<HwcSlotGenerator>::make()) {
ALOGV("Creating Layer %s", getDebugName());
mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
-
mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow;
mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp;
mDrawingState.dataspace = ui::Dataspace::V0_SRGB;
@@ -127,6 +167,20 @@
mFlinger->mFrameTracer->onDestroy(layerId);
}
+void BufferStateLayer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
+ const sp<GraphicBuffer>& buffer,
+ uint64_t framenumber,
+ const sp<Fence>& releaseFence,
+ uint32_t currentMaxAcquiredBufferCount) {
+ if (!listener) {
+ return;
+ }
+ ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber);
+ listener->onReleaseBuffer({buffer->getId(), framenumber},
+ releaseFence ? releaseFence : Fence::NO_FENCE,
+ currentMaxAcquiredBufferCount);
+}
+
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
@@ -239,14 +293,6 @@
mDrawingState.callbackHandles = {};
}
-void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
- const CompositorTiming& compositorTiming) {
- for (const auto& handle : mDrawingState.callbackHandles) {
- handle->gpuCompositionDoneFence = glDoneFence;
- handle->compositorTiming = compositorTiming;
- }
-}
-
bool BufferStateLayer::willPresentCurrentTransaction() const {
// Returns true if the most recent Transaction applied to CurrentState will be presented.
return (getSidebandStreamChanged() || getAutoRefresh() ||
@@ -307,14 +353,6 @@
return true;
}
-static bool assignTransform(ui::Transform* dst, ui::Transform& from) {
- if (*dst == from) {
- return false;
- }
- *dst = from;
- return true;
-}
-
// Translate destination frame into scale and position. If a destination frame is not set, use the
// provided scale and position
bool BufferStateLayer::updateGeometry() {
@@ -641,14 +679,6 @@
return fenceSignaled;
}
-bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const {
- if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
- return true;
- }
-
- return mDrawingState.isAutoTimestamp || mDrawingState.desiredPresentTime <= expectedPresentTime;
-}
-
bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) {
for (const auto& handle : mDrawingState.callbackHandles) {
handle->refreshStartTime = refreshStartTime;
@@ -685,8 +715,7 @@
return (mDrawingStateModified || mDrawingState.modified) && (c.buffer != nullptr || c.bgColorLayer != nullptr);
}
-status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
- nsecs_t /*expectedPresentTime*/) {
+void BufferStateLayer::updateTexImage(nsecs_t latchTime) {
const State& s(getDrawingState());
if (!s.buffer) {
@@ -695,7 +724,7 @@
handle->latchTime = latchTime;
}
}
- return NO_ERROR;
+ return;
}
for (auto& handle : mDrawingState.callbackHandles) {
@@ -734,135 +763,36 @@
mDrawingState.callbackHandles = remainingHandles;
mDrawingStateModified = false;
-
- return NO_ERROR;
}
-status_t BufferStateLayer::updateActiveBuffer() {
- const State& s(getDrawingState());
-
- if (s.buffer == nullptr) {
- return BAD_VALUE;
- }
-
- if (!mBufferInfo.mBuffer || !s.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) {
+void BufferStateLayer::gatherBufferInfo() {
+ if (!mBufferInfo.mBuffer || !mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer)) {
decrementPendingBufferCount();
}
mPreviousReleaseCallbackId = {getCurrentBufferId(), mBufferInfo.mFrameNumber};
- mBufferInfo.mBuffer = s.buffer;
- mBufferInfo.mFence = s.acquireFence;
- mBufferInfo.mFrameNumber = s.frameNumber;
-
- return NO_ERROR;
-}
-
-status_t BufferStateLayer::updateFrameNumber() {
- // TODO(marissaw): support frame history events
- mPreviousFrameNumber = mCurrentFrameNumber;
- mCurrentFrameNumber = mDrawingState.frameNumber;
- return NO_ERROR;
-}
-
-void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) {
- std::lock_guard lock(mMutex);
- if (!clientCacheId.isValid()) {
- ALOGE("invalid process, failed to erase buffer");
- return;
- }
- eraseBufferLocked(clientCacheId);
-}
-
-int BufferStateLayer::HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) {
- std::lock_guard<std::mutex> lock(mMutex);
- auto itr = mCachedBuffers.find(clientCacheId);
- if (itr == mCachedBuffers.end()) {
- return addCachedBuffer(clientCacheId);
- }
- auto& [hwcCacheSlot, counter] = itr->second;
- counter = mCounter++;
- return hwcCacheSlot;
-}
-
-int BufferStateLayer::HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId)
- REQUIRES(mMutex) {
- if (!clientCacheId.isValid()) {
- ALOGE("invalid process, returning invalid slot");
- return BufferQueue::INVALID_BUFFER_SLOT;
- }
-
- ClientCache::getInstance().registerErasedRecipient(clientCacheId, wp<ErasedRecipient>(this));
-
- int hwcCacheSlot = getFreeHwcCacheSlot();
- mCachedBuffers[clientCacheId] = {hwcCacheSlot, mCounter++};
- return hwcCacheSlot;
-}
-
-int BufferStateLayer::HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) {
- if (mFreeHwcCacheSlots.empty()) {
- evictLeastRecentlyUsed();
- }
-
- int hwcCacheSlot = mFreeHwcCacheSlots.top();
- mFreeHwcCacheSlots.pop();
- return hwcCacheSlot;
-}
-
-void BufferStateLayer::HwcSlotGenerator::evictLeastRecentlyUsed() REQUIRES(mMutex) {
- uint64_t minCounter = UINT_MAX;
- client_cache_t minClientCacheId = {};
- for (const auto& [clientCacheId, slotCounter] : mCachedBuffers) {
- const auto& [hwcCacheSlot, counter] = slotCounter;
- if (counter < minCounter) {
- minCounter = counter;
- minClientCacheId = clientCacheId;
- }
- }
- eraseBufferLocked(minClientCacheId);
-
- ClientCache::getInstance().unregisterErasedRecipient(minClientCacheId, this);
-}
-
-void BufferStateLayer::HwcSlotGenerator::eraseBufferLocked(const client_cache_t& clientCacheId)
- REQUIRES(mMutex) {
- auto itr = mCachedBuffers.find(clientCacheId);
- if (itr == mCachedBuffers.end()) {
- return;
- }
- auto& [hwcCacheSlot, counter] = itr->second;
-
- // TODO send to hwc cache and resources
-
- mFreeHwcCacheSlots.push(hwcCacheSlot);
- mCachedBuffers.erase(clientCacheId);
-}
-
-void BufferStateLayer::gatherBufferInfo() {
+ mBufferInfo.mBuffer = mDrawingState.buffer;
+ mBufferInfo.mFence = mDrawingState.acquireFence;
+ mBufferInfo.mFrameNumber = mDrawingState.frameNumber;
mBufferInfo.mPixelFormat =
!mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat();
mBufferInfo.mFrameLatencyNeeded = true;
-
- const State& s(getDrawingState());
- mBufferInfo.mDesiredPresentTime = s.desiredPresentTime;
- mBufferInfo.mFenceTime = std::make_shared<FenceTime>(s.acquireFence);
- mBufferInfo.mFence = s.acquireFence;
- mBufferInfo.mTransform = s.bufferTransform;
+ mBufferInfo.mDesiredPresentTime = mDrawingState.desiredPresentTime;
+ mBufferInfo.mFenceTime = std::make_shared<FenceTime>(mDrawingState.acquireFence);
+ mBufferInfo.mFence = mDrawingState.acquireFence;
+ mBufferInfo.mTransform = mDrawingState.bufferTransform;
auto lastDataspace = mBufferInfo.mDataspace;
- mBufferInfo.mDataspace = translateDataspace(s.dataspace);
+ mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace);
if (lastDataspace != mBufferInfo.mDataspace) {
mFlinger->mSomeDataspaceChanged = true;
}
- mBufferInfo.mCrop = computeBufferCrop(s);
+ mBufferInfo.mCrop = computeBufferCrop(mDrawingState);
mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
- mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion;
- mBufferInfo.mHdrMetadata = s.hdrMetadata;
- mBufferInfo.mApi = s.api;
- mBufferInfo.mTransformToDisplayInverse = s.transformToDisplayInverse;
- mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId);
-}
-
-uint32_t BufferStateLayer::getEffectiveScalingMode() const {
- return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
+ mBufferInfo.mSurfaceDamage = mDrawingState.surfaceDamageRegion;
+ mBufferInfo.mHdrMetadata = mDrawingState.hdrMetadata;
+ mBufferInfo.mApi = mDrawingState.api;
+ mBufferInfo.mTransformToDisplayInverse = mDrawingState.transformToDisplayInverse;
+ mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(mDrawingState.clientCacheId);
}
Rect BufferStateLayer::computeBufferCrop(const State& s) {
@@ -882,7 +812,7 @@
args.textureName = mTextureName;
sp<BufferStateLayer> layer = mFlinger->getFactory().createBufferStateLayer(args);
layer->mHwcSlotGenerator = mHwcSlotGenerator;
- layer->setInitialValuesForClone(this);
+ layer->setInitialValuesForClone(sp<Layer>::fromExisting(this));
return layer;
}
@@ -1178,32 +1108,6 @@
(mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr);
}
-bool BufferStateLayer::isFixedSize() const {
- return true;
-}
-
-bool BufferStateLayer::usesSourceCrop() const {
- return true;
-}
-
-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);
-}
-
std::optional<compositionengine::LayerFE::LayerSettings> BufferStateLayer::prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
ATRACE_CALL();
@@ -1373,38 +1277,6 @@
compositionState->sidebandStreamHasFrame = false;
}
-namespace {
-TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) {
- using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility;
- using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness;
- const auto frameRateCompatibility = [frameRate] {
- switch (frameRate.type) {
- case Layer::FrameRateCompatibility::Default:
- return FrameRateCompatibility::Default;
- case Layer::FrameRateCompatibility::ExactOrMultiple:
- return FrameRateCompatibility::ExactOrMultiple;
- default:
- return FrameRateCompatibility::Undefined;
- }
- }();
-
- const auto seamlessness = [frameRate] {
- switch (frameRate.seamlessness) {
- case scheduler::Seamlessness::OnlySeamless:
- return Seamlessness::ShouldBeSeamless;
- case scheduler::Seamlessness::SeamedAndSeamless:
- return Seamlessness::NotRequired;
- default:
- return Seamlessness::Undefined;
- }
- }();
-
- return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(),
- .frameRateCompatibility = frameRateCompatibility,
- .seamlessness = seamlessness};
-}
-} // namespace
-
void BufferStateLayer::onPostComposition(const DisplayDevice* display,
const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
@@ -1413,8 +1285,10 @@
// composition.
if (!mBufferInfo.mFrameLatencyNeeded) return;
- // Update mFrameEventHistory.
- finalizeFrameEventHistory(glDoneFence, compositorTiming);
+ for (const auto& handle : mDrawingState.callbackHandles) {
+ handle->gpuCompositionDoneFence = glDoneFence;
+ handle->compositorTiming = compositorTiming;
+ }
// Update mFrameTracker.
nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime;
@@ -1480,8 +1354,7 @@
mBufferInfo.mFrameLatencyNeeded = false;
}
-bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
- nsecs_t expectedPresentTime) {
+bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
ATRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(),
getDrawingState().frameNumber);
@@ -1499,27 +1372,16 @@
return false;
}
+ updateTexImage(latchTime);
+ if (mDrawingState.buffer == nullptr) {
+ return false;
+ }
+
// Capture the old state of the layer for comparisons later
- const State& s(getDrawingState());
- const bool oldOpacity = isOpaque(s);
-
BufferInfo oldBufferInfo = mBufferInfo;
-
- status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime);
- if (err != NO_ERROR) {
- return false;
- }
-
- err = updateActiveBuffer();
- if (err != NO_ERROR) {
- return false;
- }
-
- err = updateFrameNumber();
- if (err != NO_ERROR) {
- return false;
- }
-
+ const bool oldOpacity = isOpaque(mDrawingState);
+ mPreviousFrameNumber = mCurrentFrameNumber;
+ mCurrentFrameNumber = mDrawingState.frameNumber;
gatherBufferInfo();
if (oldBufferInfo.mBuffer == nullptr) {
@@ -1544,7 +1406,7 @@
}
}
- if (oldOpacity != isOpaque(s)) {
+ if (oldOpacity != isOpaque(mDrawingState)) {
recomputeVisibleRegions = true;
}
@@ -1628,7 +1490,7 @@
void BufferStateLayer::latchAndReleaseBuffer() {
if (hasReadyFrame()) {
bool ignored = false;
- latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */);
+ latchBuffer(ignored, systemTime());
}
releasePendingBuffer(systemTime());
}
@@ -1711,7 +1573,8 @@
void BufferStateLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
Layer::setInitialValuesForClone(clonedFrom);
- sp<BufferStateLayer> bufferClonedFrom = static_cast<BufferStateLayer*>(clonedFrom.get());
+ sp<BufferStateLayer> bufferClonedFrom =
+ sp<BufferStateLayer>::fromExisting(static_cast<BufferStateLayer*>(clonedFrom.get()));
mPremultipliedAlpha = bufferClonedFrom->mPremultipliedAlpha;
mPotentialCursor = bufferClonedFrom->mPotentialCursor;
mProtectedByApp = bufferClonedFrom->mProtectedByApp;
@@ -1724,7 +1587,8 @@
return;
}
- sp<BufferStateLayer> clonedFrom = static_cast<BufferStateLayer*>(getClonedFrom().get());
+ sp<BufferStateLayer> clonedFrom = sp<BufferStateLayer>::fromExisting(
+ static_cast<BufferStateLayer*>(getClonedFrom().get()));
mBufferInfo = clonedFrom->mBufferInfo;
mSidebandStream = clonedFrom->mSidebandStream;
surfaceDamageRegion = clonedFrom->surfaceDamageRegion;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index df7ae61..8bad3d2 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -40,6 +40,7 @@
#include "DisplayHardware/HWComposer.h"
#include "FrameTimeline.h"
#include "FrameTracker.h"
+#include "HwcSlotGenerator.h"
#include "Layer.h"
#include "LayerVector.h"
#include "SurfaceFlinger.h"
@@ -74,10 +75,7 @@
// GRALLOC_USAGE_PROTECTED sense.
bool isProtected() const override;
- // isFixedSize - true if content has a fixed size
- bool isFixedSize() const override;
-
- bool usesSourceCrop() const override;
+ bool usesSourceCrop() const override { return true; }
bool isHdrY410() const override;
@@ -89,13 +87,9 @@
// the visible regions need to be recomputed (this is a fairly heavy
// operation, so this should be set only if needed). Typically this is used
// to figure out if the content or size of a surface has changed.
- bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
- nsecs_t expectedPresentTime) override;
+ bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
bool hasReadyFrame() const override;
- // Returns the current scaling mode
- uint32_t getEffectiveScalingMode() const override;
-
// Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
// This is used if the buffer is just latched and releases to free up the buffer
// and will not be shown on screen.
@@ -122,14 +116,6 @@
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
- void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
- const CompositorTiming& compositorTiming) override;
-
- // Returns true if the next buffer should be presented at the expected present time,
- // overridden by BufferStateLayer and BufferQueueLayer for implementation
- // specific logic
- bool isBufferDue(nsecs_t /*expectedPresentTime*/) const { return true; }
-
Region getActiveTransparentRegion(const Layer::State& s) const override {
return s.transparentRegionHint;
}
@@ -166,7 +152,6 @@
bool updateGeometry() override;
bool fenceHasSignaled() const;
- bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const;
bool onPreComposition(nsecs_t) override;
// See mPendingBufferTransactions
@@ -174,9 +159,6 @@
std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; }
std::string getPendingBufferCounterName() override { return mBlastTransactionName; }
- // Returns true if the next buffer should be presented at the expected present time
- bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const override { return true; }
-
protected:
void gatherBufferInfo();
void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame);
@@ -268,11 +250,7 @@
bool hasFrameUpdate() const;
- status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
- nsecs_t expectedPresentTime);
-
- status_t updateActiveBuffer();
- status_t updateFrameNumber();
+ void updateTexImage(nsecs_t latchTime);
sp<Layer> createClone() override;
@@ -323,45 +301,6 @@
// not specify a destination frame.
ui::Transform mRequestedTransform;
- // TODO(marissaw): support sticky transform for LEGACY camera mode
-
- class HwcSlotGenerator : public ClientCache::ErasedRecipient {
- public:
- HwcSlotGenerator() {
- for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- mFreeHwcCacheSlots.push(i);
- }
- }
-
- void bufferErased(const client_cache_t& clientCacheId);
-
- int getHwcCacheSlot(const client_cache_t& clientCacheId);
-
- private:
- friend class SlotGenerationTest;
- int addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex);
- int getFreeHwcCacheSlot() REQUIRES(mMutex);
- void evictLeastRecentlyUsed() REQUIRES(mMutex);
- void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex);
-
- struct CachedBufferHash {
- std::size_t operator()(const client_cache_t& clientCacheId) const {
- return std::hash<uint64_t>{}(clientCacheId.id);
- }
- };
-
- std::mutex mMutex;
-
- std::unordered_map<client_cache_t, std::pair<int /*HwcCacheSlot*/, uint64_t /*counter*/>,
- CachedBufferHash>
- mCachedBuffers GUARDED_BY(mMutex);
- std::stack<int /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex);
-
- // The cache increments this counter value when a slot is updated or used.
- // Used to track the least recently-used buffer
- uint64_t mCounter = 0;
- };
-
sp<HwcSlotGenerator> mHwcSlotGenerator;
};
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index b27055d..3685bb4 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -83,8 +83,8 @@
sp<IBinder> handle;
int32_t layerId;
uint32_t transformHint;
- LayerCreationArgs args(mFlinger.get(), this, name.c_str(), static_cast<uint32_t>(flags),
- std::move(metadata));
+ LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), name.c_str(),
+ static_cast<uint32_t>(flags), std::move(metadata));
const status_t status =
mFlinger->createLayer(args, &handle, parent, &layerId, nullptr, &transformHint);
if (status == NO_ERROR) {
@@ -137,7 +137,8 @@
gui::MirrorSurfaceResult* outResult) {
sp<IBinder> handle;
int32_t layerId;
- LayerCreationArgs args(mFlinger.get(), this, "MirrorRoot", 0 /* flags */, gui::LayerMetadata());
+ LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), "MirrorRoot",
+ 0 /* flags */, gui::LayerMetadata());
status_t status = mFlinger->mirrorLayer(args, mirrorFromHandle, &handle, &layerId);
if (status == NO_ERROR) {
outResult->handle = handle;
@@ -146,5 +147,20 @@
return binderStatusFromStatusT(status);
}
+binder::Status Client::mirrorDisplay(int64_t displayId, gui::MirrorSurfaceResult* outResult) {
+ sp<IBinder> handle;
+ int32_t layerId;
+ LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this),
+ "MirrorRoot-" + std::to_string(displayId), 0 /* flags */,
+ gui::LayerMetadata());
+ std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId));
+ status_t status = mFlinger->mirrorDisplay(*id, args, &handle, &layerId);
+ if (status == NO_ERROR) {
+ outResult->handle = handle;
+ outResult->layerId = layerId;
+ }
+ return binderStatusFromStatusT(status);
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 4720d5c..4e59dfd 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -59,6 +59,8 @@
binder::Status mirrorSurface(const sp<IBinder>& mirrorFromHandle,
gui::MirrorSurfaceResult* outResult) override;
+ binder::Status mirrorDisplay(int64_t displayId, gui::MirrorSurfaceResult* outResult) override;
+
// constant
sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/ClientCache.cpp b/services/surfaceflinger/ClientCache.cpp
index 3c7b9d9..cf932a8 100644
--- a/services/surfaceflinger/ClientCache.cpp
+++ b/services/surfaceflinger/ClientCache.cpp
@@ -30,7 +30,7 @@
ANDROID_SINGLETON_STATIC_INSTANCE(ClientCache);
-ClientCache::ClientCache() : mDeathRecipient(new CacheDeathRecipient) {}
+ClientCache::ClientCache() : mDeathRecipient(sp<CacheDeathRecipient>::make()) {}
bool ClientCache::getBuffer(const client_cache_t& cacheId,
ClientCacheBuffer** outClientCacheBuffer) {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index 9ee779c..5854674 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -91,16 +91,9 @@
// Called after the HWC calls are made to present the display
virtual void onPresentDisplayCompleted() = 0;
- // Called after the surface has been rendering to signal the surface should
- // be made ready for displaying
- virtual void flip() = 0;
-
// Debugging - Dumps the state of the RenderSurface to a string
virtual void dump(std::string& result) const = 0;
- // Debugging - gets the page flip count for the RenderSurface
- virtual std::uint32_t getPageFlipCount() const = 0;
-
// Returns true if the render surface supports client composition prediction.
virtual bool supportsCompositionStrategyPrediction() const = 0;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index e4cb113..1c14a43 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -62,15 +62,12 @@
base::unique_fd* bufferFence) override;
void queueBuffer(base::unique_fd readyFence) override;
void onPresentDisplayCompleted() override;
- void flip() override;
bool supportsCompositionStrategyPrediction() const override;
// Debugging
void dump(std::string& result) const override;
- std::uint32_t getPageFlipCount() const override;
// Testing
- void setPageFlipCountForTest(std::uint32_t);
void setSizeForTest(const ui::Size&);
std::shared_ptr<renderengine::ExternalTexture>& mutableTextureForTest();
base::unique_fd& mutableBufferReadyForTest();
@@ -89,7 +86,6 @@
ui::Size mSize;
const size_t mMaxTextureCacheSize;
bool mProtected{false};
- std::uint32_t mPageFlipCount{0};
};
std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index e65aa73..2bfd3cf 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -150,8 +150,6 @@
bool hasSolidColorLayers() const;
private:
- CachedSet() = default;
-
const NonBufferHash mFingerprint;
std::chrono::steady_clock::time_point mLastUpdate = std::chrono::steady_clock::now();
std::vector<Layer> mLayers;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index e12aebb..af8d4bc 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -42,9 +42,7 @@
MOCK_METHOD1(dequeueBuffer, std::shared_ptr<renderengine::ExternalTexture>(base::unique_fd*));
MOCK_METHOD1(queueBuffer, void(base::unique_fd));
MOCK_METHOD0(onPresentDisplayCompleted, void());
- MOCK_METHOD0(flip, void());
MOCK_CONST_METHOD1(dump, void(std::string& result));
- MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
MOCK_CONST_METHOD0(supportsCompositionStrategyPrediction, bool());
};
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index ea856e4..09adaed 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -196,7 +196,7 @@
});
if (hasQueuedFrames) {
- releasedLayers.emplace_back(layerFE);
+ releasedLayers.emplace_back(wp<LayerFE>::fromExisting(layerFE));
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index aea6798..8ebc5b1 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1160,7 +1160,8 @@
if (isPowerHintSessionEnabled()) {
// get fence end time to know when gpu is complete in display
- setHintSessionGpuFence(std::make_unique<FenceTime>(new Fence(dup(optReadyFence->get()))));
+ setHintSessionGpuFence(
+ std::make_unique<FenceTime>(sp<Fence>::make(dup(optReadyFence->get()))));
}
// swap buffers (presentation)
mRenderSurface->queueBuffer(std::move(*optReadyFence));
@@ -1288,7 +1289,8 @@
ATRACE_NAME("ClientCompositionCacheHit");
outputCompositionState.reusedClientComposition = true;
setExpensiveRenderingExpected(false);
- return base::unique_fd();
+ // b/239944175 pass the fence associated with the buffer.
+ return base::unique_fd(std::move(fd));
}
ATRACE_NAME("ClientCompositionCacheMiss");
mClientCompositionRequestCache->add(tex->getBuffer()->getId(), clientCompositionDisplay,
@@ -1491,7 +1493,6 @@
auto& outputState = editState();
outputState.dirtyRegion.clear();
- mRenderSurface->flip();
auto frame = presentAndGetFrameFences();
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 5a3af7b..0fe55db 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -251,10 +251,6 @@
mDisplaySurface->onFrameCommitted();
}
-void RenderSurface::flip() {
- mPageFlipCount++;
-}
-
void RenderSurface::dump(std::string& out) const {
using android::base::StringAppendF;
@@ -265,7 +261,6 @@
dumpVal(out, "size", mSize);
StringAppendF(&out, "ANativeWindow=%p (format %d) ", mNativeWindow.get(),
ANativeWindow_getFormat(mNativeWindow.get()));
- dumpVal(out, "flips", mPageFlipCount);
out.append("\n");
String8 surfaceDump;
@@ -273,14 +268,6 @@
out.append(surfaceDump);
}
-std::uint32_t RenderSurface::getPageFlipCount() const {
- return mPageFlipCount;
-}
-
-void RenderSurface::setPageFlipCountForTest(std::uint32_t count) {
- mPageFlipCount = count;
-}
-
void RenderSurface::setSizeForTest(const ui::Size& size) {
mSize = size;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 344fea3..51ca213 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -194,7 +194,7 @@
StrictMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor;
StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
StrictMock<mock::CompositionEngine> mCompositionEngine;
- sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
+ sp<mock::NativeWindow> mNativeWindow = sp<StrictMock<mock::NativeWindow>>::make();
};
struct PartialMockDisplayTestCommon : public DisplayTestCommon {
@@ -524,7 +524,7 @@
auto args = getDisplayCreationArgsForGpuVirtualDisplay();
std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args);
- sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
+ sp<mock::LayerFE> layerXLayerFE = sp<StrictMock<mock::LayerFE>>::make();
{
Output::ReleasedLayers releasedLayers;
@@ -542,7 +542,7 @@
}
TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNoLayersWithQueuedFrames) {
- sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
+ sp<mock::LayerFE> layerXLayerFE = sp<StrictMock<mock::LayerFE>>::make();
{
Output::ReleasedLayers releasedLayers;
@@ -558,7 +558,7 @@
}
TEST_F(DisplaySetReleasedLayersTest, setReleasedLayers) {
- sp<mock::LayerFE> unknownLayer = new StrictMock<mock::LayerFE>();
+ sp<mock::LayerFE> unknownLayer = sp<StrictMock<mock::LayerFE>>::make();
CompositionRefreshArgs refreshArgs;
refreshArgs.layersWithQueuedFrames.push_back(mLayer1.layerFE);
@@ -897,9 +897,9 @@
}
TEST_F(DisplayPresentAndGetFrameFencesTest, returnsPresentAndLayerFences) {
- sp<Fence> presentFence = new Fence();
- sp<Fence> layer1Fence = new Fence();
- sp<Fence> layer2Fence = new Fence();
+ sp<Fence> presentFence = sp<Fence>::make();
+ sp<Fence> layer1Fence = sp<Fence>::make();
+ sp<Fence> layer2Fence = sp<Fence>::make();
EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(HalDisplayId(DEFAULT_DISPLAY_ID), _, _))
.Times(1);
@@ -1018,8 +1018,8 @@
NiceMock<android::mock::HWComposer> mHwComposer;
NiceMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor;
NiceMock<mock::CompositionEngine> mCompositionEngine;
- sp<mock::NativeWindow> mNativeWindow = new NiceMock<mock::NativeWindow>();
- sp<mock::DisplaySurface> mDisplaySurface = new NiceMock<mock::DisplaySurface>();
+ sp<mock::NativeWindow> mNativeWindow = sp<NiceMock<mock::NativeWindow>>::make();
+ sp<mock::DisplaySurface> mDisplaySurface = sp<NiceMock<mock::DisplaySurface>>::make();
std::shared_ptr<Display> mDisplay;
impl::RenderSurface* mRenderSurface;
diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
index 00eafb1..7197780 100644
--- a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
@@ -66,8 +66,10 @@
}
impl::HwcBufferCache mCache;
- sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
- sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ sp<GraphicBuffer> mBuffer1 =
+ sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
+ sp<GraphicBuffer> mBuffer2 =
+ sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
};
TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index 8c164ed..c8bd5e4 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -55,7 +55,8 @@
MOCK_METHOD(void, setRequiresClientComposition,
(DisplayId displayId, bool requiresClientComposition), (override));
MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override));
- MOCK_METHOD(void, setPresentFenceTime, (nsecs_t presentFenceTime), (override));
+ MOCK_METHOD(void, setSfPresentTiming, (nsecs_t presentFenceTime, nsecs_t presentEndTime),
+ (override));
MOCK_METHOD(void, setHwcPresentDelayedTime,
(DisplayId displayId,
std::chrono::steady_clock::time_point earliestFrameStartTime));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 5290bd9..0f7dce8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -955,11 +955,11 @@
reinterpret_cast<native_handle_t*>(1031);
const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer;
const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kOverrideBuffer =
- new GraphicBuffer(4, 5, PIXEL_FORMAT_RGBA_8888,
- AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
- AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
+ sp<GraphicBuffer>::make(4, 5, PIXEL_FORMAT_RGBA_8888,
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
+ AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
const sp<Fence> OutputLayerWriteStateToHWCTest::kFence;
-const sp<Fence> OutputLayerWriteStateToHWCTest::kOverrideFence = new Fence();
+const sp<Fence> OutputLayerWriteStateToHWCTest::kOverrideFence = sp<Fence>::make();
const std::string OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Key =
"com.example.metadata.1";
const std::vector<uint8_t> OutputLayerWriteStateToHWCTest::kLayerGenericMetadata1Value{{1, 2, 3}};
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index cf12890..ad0fb9d 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -293,7 +293,7 @@
InjectedLayer layer;
layer.outputLayerState.overrideInfo.buffer = std::make_shared<
renderengine::impl::
- ExternalTexture>(new GraphicBuffer(), renderEngine,
+ ExternalTexture>(sp<GraphicBuffer>::make(), renderEngine,
renderengine::impl::ExternalTexture::Usage::READABLE |
renderengine::impl::ExternalTexture::Usage::WRITEABLE);
injectOutputLayer(layer);
@@ -1017,7 +1017,7 @@
std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared<
renderengine::impl::
- ExternalTexture>(new GraphicBuffer(), renderEngine,
+ ExternalTexture>(sp<GraphicBuffer>::make(), renderEngine,
renderengine::impl::ExternalTexture::Usage::READABLE |
renderengine::impl::ExternalTexture::Usage::WRITEABLE);
layer1.outputLayerState.overrideInfo.buffer = buffer;
@@ -3227,7 +3227,6 @@
// setup below are satisfied in the specific order.
InSequence seq;
- EXPECT_CALL(*mRenderSurface, flip());
EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences));
EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
@@ -3250,7 +3249,6 @@
frameFences.layerFences.emplace(&mLayer2.hwc2Layer, layer2Fence);
frameFences.layerFences.emplace(&mLayer3.hwc2Layer, layer3Fence);
- EXPECT_CALL(*mRenderSurface, flip());
EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences));
EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
@@ -3284,7 +3282,6 @@
frameFences.layerFences.emplace(&mLayer2.hwc2Layer, sp<Fence>::make());
frameFences.layerFences.emplace(&mLayer3.hwc2Layer, sp<Fence>::make());
- EXPECT_CALL(*mRenderSurface, flip());
EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences));
EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
@@ -3320,7 +3317,6 @@
Output::FrameFences frameFences;
frameFences.presentFence = presentFence;
- EXPECT_CALL(*mRenderSurface, flip());
EXPECT_CALL(mOutput, presentAndGetFrameFences()).WillOnce(Return(frameFences));
EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
@@ -3449,7 +3445,7 @@
StrictMock<OutputPartialMock> mOutput;
std::shared_ptr<renderengine::ExternalTexture> mOutputBuffer = std::make_shared<
renderengine::impl::
- ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+ ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine,
renderengine::impl::ExternalTexture::Usage::READABLE |
renderengine::impl::ExternalTexture::Usage::WRITEABLE);
@@ -3687,7 +3683,7 @@
const auto otherOutputBuffer = std::make_shared<
renderengine::impl::
- ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+ ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine,
renderengine::impl::ExternalTexture::Usage::READABLE |
renderengine::impl::ExternalTexture::Usage::WRITEABLE);
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index e5f9ebf..83937a6 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -61,8 +61,8 @@
StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
StrictMock<mock::CompositionEngine> mCompositionEngine;
StrictMock<mock::Display> mDisplay;
- sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
- sp<mock::DisplaySurface> mDisplaySurface = new StrictMock<mock::DisplaySurface>();
+ sp<mock::NativeWindow> mNativeWindow = sp<StrictMock<mock::NativeWindow>>::make();
+ sp<mock::DisplaySurface> mDisplaySurface = sp<StrictMock<mock::DisplaySurface>>::make();
impl::RenderSurface mSurface{mCompositionEngine, mDisplay,
RenderSurfaceCreationArgsBuilder()
.setDisplayWidth(DEFAULT_DISPLAY_WIDTH)
@@ -109,7 +109,7 @@
*/
TEST_F(RenderSurfaceTest, getClientTargetAcquireFenceForwardsCall) {
- sp<Fence> fence = new Fence();
+ sp<Fence> fence = sp<Fence>::make();
EXPECT_CALL(*mDisplaySurface, getClientTargetAcquireFence()).WillOnce(ReturnRef(fence));
@@ -234,7 +234,7 @@
*/
TEST_F(RenderSurfaceTest, dequeueBufferObtainsABuffer) {
- sp<GraphicBuffer> buffer = new GraphicBuffer();
+ sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make();
EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
.WillOnce(
@@ -253,7 +253,7 @@
TEST_F(RenderSurfaceTest, queueBufferHandlesNoClientComposition) {
const auto buffer = std::make_shared<
renderengine::impl::
- ExternalTexture>(new GraphicBuffer(), mRenderEngine,
+ ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine,
renderengine::impl::ExternalTexture::Usage::READABLE |
renderengine::impl::ExternalTexture::Usage::WRITEABLE);
mSurface.mutableTextureForTest() = buffer;
@@ -271,8 +271,9 @@
}
TEST_F(RenderSurfaceTest, queueBufferHandlesClientComposition) {
- const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(),
- mRenderEngine, false);
+ const auto buffer =
+ std::make_shared<renderengine::impl::ExternalTexture>(sp<GraphicBuffer>::make(),
+ mRenderEngine, false);
mSurface.mutableTextureForTest() = buffer;
impl::OutputCompositionState state;
@@ -290,8 +291,9 @@
}
TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequest) {
- const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(),
- mRenderEngine, false);
+ const auto buffer =
+ std::make_shared<renderengine::impl::ExternalTexture>(sp<GraphicBuffer>::make(),
+ mRenderEngine, false);
mSurface.mutableTextureForTest() = buffer;
impl::OutputCompositionState state;
@@ -309,7 +311,7 @@
}
TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) {
- sp<GraphicBuffer> buffer = new GraphicBuffer();
+ sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make();
impl::OutputCompositionState state;
state.usesClientComposition = false;
@@ -329,8 +331,9 @@
}
TEST_F(RenderSurfaceTest, queueBufferHandlesNativeWindowQueueBufferFailureOnVirtualDisplay) {
- const auto buffer = std::make_shared<renderengine::impl::ExternalTexture>(new GraphicBuffer(),
- mRenderEngine, false);
+ const auto buffer =
+ std::make_shared<renderengine::impl::ExternalTexture>(sp<GraphicBuffer>::make(),
+ mRenderEngine, false);
mSurface.mutableTextureForTest() = buffer;
impl::OutputCompositionState state;
@@ -359,17 +362,5 @@
mSurface.onPresentDisplayCompleted();
}
-/*
- * RenderSurface::flip()
- */
-
-TEST_F(RenderSurfaceTest, flipForwardsSignal) {
- mSurface.setPageFlipCountForTest(500);
-
- mSurface.flip();
-
- EXPECT_EQ(501u, mSurface.getPageFlipCount());
-}
-
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 50e3a28..200278c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -108,11 +108,12 @@
testLayer->outputLayerCompositionState.visibleRegion =
Region(Rect(pos + 1, pos + 1, pos + 2, pos + 2));
+ const auto kUsageFlags =
+ static_cast<uint64_t>(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE);
testLayer->layerFECompositionState.buffer =
- new GraphicBuffer(100, 100, HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE,
- "output");
+ sp<GraphicBuffer>::make(100u, 100u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags,
+ "output");
testLayer->layerFE = sp<mock::LayerFE>::make();
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
index 5c6e8da..47b6820 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
@@ -112,6 +112,9 @@
sp<mock::LayerFE> mLayerFE = sp<mock::LayerFE>::make();
mock::OutputLayer mOutputLayer;
std::unique_ptr<LayerState> mLayerState;
+
+ static constexpr auto kUsageFlags = static_cast<uint32_t>(
+ AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN);
};
TEST_F(LayerStateTest, getOutputLayer) {
@@ -346,7 +349,7 @@
TEST_F(LayerStateTest, updateBuffer) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- layerFECompositionState.buffer = new GraphicBuffer();
+ layerFECompositionState.buffer = sp<GraphicBuffer>::make();
setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -354,7 +357,7 @@
mock::OutputLayer newOutputLayer;
sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
- layerFECompositionStateTwo.buffer = new GraphicBuffer();
+ layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
@@ -364,7 +367,7 @@
TEST_F(LayerStateTest, updateBufferSingleBufferedLegacy) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- layerFECompositionState.buffer = new GraphicBuffer();
+ layerFECompositionState.buffer = sp<GraphicBuffer>::make();
setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -372,7 +375,7 @@
mock::OutputLayer newOutputLayer;
sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
- layerFECompositionStateTwo.buffer = new GraphicBuffer();
+ layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
@@ -388,7 +391,7 @@
TEST_F(LayerStateTest, updateBufferSingleBufferedUsage) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- layerFECompositionState.buffer = new GraphicBuffer();
+ layerFECompositionState.buffer = sp<GraphicBuffer>::make();
setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -396,7 +399,7 @@
mock::OutputLayer newOutputLayer;
sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
- layerFECompositionStateTwo.buffer = new GraphicBuffer();
+ layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
layerFECompositionStateTwo.buffer->usage = static_cast<uint64_t>(BufferUsage::FRONT_BUFFER);
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
@@ -412,14 +415,14 @@
TEST_F(LayerStateTest, compareBuffer) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- layerFECompositionState.buffer = new GraphicBuffer();
+ layerFECompositionState.buffer = sp<GraphicBuffer>::make();
setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
mock::OutputLayer newOutputLayer;
sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
- layerFECompositionStateTwo.buffer = new GraphicBuffer();
+ layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -720,10 +723,7 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.buffer =
- new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888,
- AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
- AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
- "buffer1");
+ sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888, kUsageFlags, "buffer1");
setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -732,10 +732,7 @@
sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.buffer =
- new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBX_8888,
- AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
- AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
- "buffer2");
+ sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBX_8888, kUsageFlags, "buffer2");
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
@@ -748,10 +745,7 @@
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
layerFECompositionState.buffer =
- new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888,
- AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
- AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
- "buffer1");
+ sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888, kUsageFlags, "buffer1");
setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -759,10 +753,7 @@
sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
layerFECompositionStateTwo.buffer =
- new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBX_8888,
- AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
- AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
- "buffer2");
+ sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBX_8888, kUsageFlags, "buffer2");
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
@@ -1069,7 +1060,7 @@
TEST_F(LayerStateTest, getNonBufferHash_filtersOutBuffers) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
- layerFECompositionState.buffer = new GraphicBuffer();
+ layerFECompositionState.buffer = sp<GraphicBuffer>::make();
setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
layerFECompositionState);
mLayerState = std::make_unique<LayerState>(&mOutputLayer);
@@ -1077,7 +1068,7 @@
mock::OutputLayer newOutputLayer;
sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
LayerFECompositionState layerFECompositionStateTwo;
- layerFECompositionStateTwo.buffer = new GraphicBuffer();
+ layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
layerFECompositionStateTwo);
auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
index 68c72e0..35d0ffb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/PredictorTest.cpp
@@ -228,7 +228,7 @@
}
TEST_F(LayerStackTest, getApproximateMatch_exactMatchesSameBuffer) {
- sp<GraphicBuffer> buffer = new GraphicBuffer();
+ sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make();
mock::OutputLayer outputLayerOne;
sp<mock::LayerFE> layerFEOne = sp<mock::LayerFE>::make();
OutputLayerCompositionState outputLayerCompositionStateOne;
@@ -268,7 +268,7 @@
.dataspace = ui::Dataspace::SRGB,
};
LayerFECompositionState layerFECompositionStateOne;
- layerFECompositionStateOne.buffer = new GraphicBuffer();
+ layerFECompositionStateOne.buffer = sp<GraphicBuffer>::make();
layerFECompositionStateOne.alpha = sAlphaOne;
layerFECompositionStateOne.colorTransformIsIdentity = true;
setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
@@ -285,7 +285,7 @@
.dataspace = ui::Dataspace::DISPLAY_P3,
};
LayerFECompositionState layerFECompositionStateTwo;
- layerFECompositionStateTwo.buffer = new GraphicBuffer();
+ layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
layerFECompositionStateTwo.alpha = sAlphaTwo;
layerFECompositionStateTwo.colorTransformIsIdentity = false;
layerFECompositionStateTwo.colorTransform = sMat4One;
@@ -310,7 +310,7 @@
.sourceCrop = sFloatRectOne,
};
LayerFECompositionState layerFECompositionStateOne;
- layerFECompositionStateOne.buffer = new GraphicBuffer();
+ layerFECompositionStateOne.buffer = sp<GraphicBuffer>::make();
setupMocksForLayer(outputLayerOne, *layerFEOne, outputLayerCompositionStateOne,
layerFECompositionStateOne);
LayerState layerStateOne(&outputLayerOne);
@@ -321,7 +321,7 @@
.sourceCrop = sFloatRectTwo,
};
LayerFECompositionState layerFECompositionStateTwo;
- layerFECompositionStateTwo.buffer = new GraphicBuffer();
+ layerFECompositionStateTwo.buffer = sp<GraphicBuffer>::make();
setupMocksForLayer(outputLayerTwo, *layerFETwo, outputLayerCompositionStateTwo,
layerFECompositionStateTwo);
LayerState layerStateTwo(&outputLayerTwo);
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
deleted file mode 100644
index 3ccc229..0000000
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-// #define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "ContainerLayer"
-
-#include "ContainerLayer.h"
-
-namespace android {
-
-ContainerLayer::ContainerLayer(const LayerCreationArgs& args) : Layer(args) {}
-
-ContainerLayer::~ContainerLayer() = default;
-
-bool ContainerLayer::isVisible() const {
- return false;
-}
-
-sp<Layer> ContainerLayer::createClone() {
- sp<ContainerLayer> layer = mFlinger->getFactory().createContainerLayer(
- LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()));
- layer->setInitialValuesForClone(this);
- return layer;
-}
-
-} // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
deleted file mode 100644
index 9b7bab1..0000000
--- a/services/surfaceflinger/ContainerLayer.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <sys/types.h>
-
-#include <cstdint>
-
-#include "Layer.h"
-
-namespace android {
-
-class ContainerLayer : public Layer {
-public:
- explicit ContainerLayer(const LayerCreationArgs&);
- ~ContainerLayer() override;
-
- const char* getType() const override { return "ContainerLayer"; }
- bool isVisible() const override;
-
- bool isCreatedFromMainThread() const override { return true; }
-
-protected:
- bool canDrawShadows() const override { return false; }
- sp<Layer> createClone() override;
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 8680900..bff301e 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -136,10 +136,6 @@
mDeviceProductInfo = std::move(info);
}
-uint32_t DisplayDevice::getPageFlipCount() const {
- return mCompositionDisplay->getRenderSurface()->getPageFlipCount();
-}
-
auto DisplayDevice::getInputInfo() const -> InputInfo {
gui::DisplayInfo info;
info.displayId = getLayerStack().id;
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 2161436..10fc095 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -259,7 +259,6 @@
/* ------------------------------------------------------------------------
* Debugging
*/
- uint32_t getPageFlipCount() const;
std::string getDebugName() const;
void dump(std::string& result) const;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index c52e96d..16d3984 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -369,7 +369,7 @@
for (uint32_t element = 0; element < numElements; ++element) {
auto layer = getLayerById(layerIds[element]);
if (layer) {
- sp<Fence> fence(new Fence(fenceFds[element]));
+ sp<Fence> fence(sp<Fence>::make(fenceFds[element]));
releaseFences.emplace(layer.get(), fence);
} else {
ALOGE("getReleaseFences: invalid layer %" PRIu64
@@ -394,7 +394,7 @@
return error;
}
- *outPresentFence = new Fence(presentFenceFd);
+ *outPresentFence = sp<Fence>::make(presentFenceFd);
return Error::NONE;
}
@@ -532,7 +532,7 @@
}
if (*state == 1) {
- *outPresentFence = new Fence(presentFenceFd);
+ *outPresentFence = sp<Fence>::make(presentFenceFd);
}
if (*state == 0) {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 77dda6c..929f9dc 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -187,7 +187,7 @@
if (!mSupportsPowerHint.has_value()) {
std::lock_guard lock(mPowerHalMutex);
HalWrapper* const halWrapper = getPowerHal();
- mSupportsPowerHint = halWrapper->supportsPowerHintSession();
+ mSupportsPowerHint = halWrapper && halWrapper->supportsPowerHintSession();
}
return *mSupportsPowerHint;
}
@@ -315,7 +315,8 @@
mExpectedPresentTimes.append(expectedPresentTime);
}
-void PowerAdvisor::setPresentFenceTime(nsecs_t presentFenceTime) {
+void PowerAdvisor::setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) {
+ mLastSfPresentEndTime = presentEndTime;
mLastPresentFenceTime = presentFenceTime;
}
@@ -334,13 +335,7 @@
}
void PowerAdvisor::setCompositeEnd(nsecs_t compositeEnd) {
- mLastCompositeEndTime = compositeEnd;
- // calculate the postcomp time here as well
- std::vector<DisplayId>&& displays = getOrderedDisplayIds(&DisplayTimingData::hwcPresentEndTime);
- DisplayTimingData& timingData = mDisplayTimingData[displays.back()];
- mLastPostcompDuration = compositeEnd -
- (timingData.skippedValidate ? *timingData.hwcValidateEndTime
- : *timingData.hwcPresentEndTime);
+ mLastPostcompDuration = compositeEnd - mLastSfPresentEndTime;
}
void PowerAdvisor::setDisplays(std::vector<DisplayId>& displayIds) {
@@ -399,7 +394,7 @@
getOrderedDisplayIds(&DisplayTimingData::hwcPresentStartTime);
DisplayTimeline referenceTiming, estimatedTiming;
- // Iterate over the displays in the same order they are presented
+ // Iterate over the displays that use hwc in the same order they are presented
for (DisplayId displayId : displayIds) {
if (mDisplayTimingData.count(displayId) == 0) {
continue;
@@ -451,8 +446,11 @@
}
ATRACE_INT64("Idle duration", idleDuration);
+ nsecs_t estimatedFlingerEndTime = earlyHint ? estimatedEndTime : mLastSfPresentEndTime;
+
// Don't count time spent idly waiting in the estimate as we could do more work in that time
estimatedEndTime -= idleDuration;
+ estimatedFlingerEndTime -= idleDuration;
// We finish the frame when both present and the gpu are done, so wait for the later of the two
// Also add the frame delay duration since the target did not move while we were delayed
@@ -460,7 +458,10 @@
std::max(estimatedEndTime, estimatedGpuEndTime.value_or(0)) - mCommitStartTimes[0];
// We finish SurfaceFlinger when post-composition finishes, so add that in here
- nsecs_t flingerDuration = estimatedEndTime + mLastPostcompDuration - mCommitStartTimes[0];
+ nsecs_t flingerDuration =
+ estimatedFlingerEndTime + mLastPostcompDuration - mCommitStartTimes[0];
+
+ // Combine the two timings into a single normalized one
nsecs_t combinedDuration = combineTimingEstimates(totalDuration, flingerDuration);
return std::make_optional(combinedDuration);
@@ -640,9 +641,8 @@
mSupportsPowerHint = checkPowerHintSessionSupported();
- mAllowedActualDeviation =
- base::GetIntProperty<nsecs_t>("debug.sf.allowed_actual_deviation",
- std::chrono::nanoseconds(250us).count());
+ // Currently set to 0 to disable rate limiter by default
+ mAllowedActualDeviation = base::GetIntProperty<nsecs_t>("debug.sf.allowed_actual_deviation", 0);
}
AidlPowerHalWrapper::~AidlPowerHalWrapper() {
@@ -759,9 +759,10 @@
}
bool AidlPowerHalWrapper::shouldReportActualDurations() {
- // Report if we have never reported before or are approaching a stale session
+ // Report if we have never reported before or will go stale next frame
if (!mLastActualDurationSent.has_value() ||
- (systemTime() - mLastActualReportTimestamp) > kStaleTimeout.count()) {
+ (mLastTargetDurationSent + systemTime() - mLastActualReportTimestamp) >
+ kStaleTimeout.count()) {
return true;
}
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 98921b0..859cf3d 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -72,8 +72,8 @@
nsecs_t presentEndTime) = 0;
// Reports the expected time that the current frame will present to the display
virtual void setExpectedPresentTime(nsecs_t expectedPresentTime) = 0;
- // Reports the most recent present fence time once it's known at the end of the frame
- virtual void setPresentFenceTime(nsecs_t presentFenceTime) = 0;
+ // Reports the most recent present fence time and end time once known
+ virtual void setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) = 0;
// Reports whether a display used client composition this frame
virtual void setRequiresClientComposition(DisplayId displayId,
bool requiresClientComposition) = 0;
@@ -142,7 +142,7 @@
void setSkippedValidate(DisplayId displayId, bool skipped) override;
void setRequiresClientComposition(DisplayId displayId, bool requiresClientComposition) override;
void setExpectedPresentTime(nsecs_t expectedPresentTime) override;
- void setPresentFenceTime(nsecs_t presentFenceTime) override;
+ void setSfPresentTiming(nsecs_t presentFenceTime, nsecs_t presentEndTime) override;
void setHwcPresentDelayedTime(
DisplayId displayId,
std::chrono::steady_clock::time_point earliestFrameStartTime) override;
@@ -245,8 +245,6 @@
// Current frame's delay
nsecs_t mFrameDelayDuration = 0;
- // Last frame's composite end time
- nsecs_t mLastCompositeEndTime = -1;
// Last frame's post-composition duration
nsecs_t mLastPostcompDuration = 0;
// Buffer of recent commit start times
@@ -255,6 +253,8 @@
RingBuffer<nsecs_t, 2> mExpectedPresentTimes;
// Most recent present fence time, set at the end of the frame once known
nsecs_t mLastPresentFenceTime = -1;
+ // Most recent present fence time, set at the end of the frame once known
+ nsecs_t mLastSfPresentEndTime = -1;
// Target for the entire pipeline including gpu
std::optional<nsecs_t> mTotalFrameTargetDuration;
// Updated list of display IDs
@@ -332,7 +332,7 @@
static const bool sTraceHintSessionData;
static constexpr const std::chrono::nanoseconds kDefaultTarget = 16ms;
// Amount of time after the last message was sent before the session goes stale
- // actually 100ms but we use 80 here to ideally avoid going stale
+ // actually 100ms but we use 80 here to give some slack
static constexpr const std::chrono::nanoseconds kStaleTimeout = 80ms;
};
diff --git a/services/surfaceflinger/EffectLayer.cpp b/services/surfaceflinger/EffectLayer.cpp
index e8c590e..d8bbc30 100644
--- a/services/surfaceflinger/EffectLayer.cpp
+++ b/services/surfaceflinger/EffectLayer.cpp
@@ -74,7 +74,7 @@
}
bool EffectLayer::isVisible() const {
- return !isHiddenByPolicy() && (getAlpha() > 0.0_hf || hasBlur()) && hasSomethingToDraw();
+ return hasSomethingToDraw() && !isHiddenByPolicy() && (getAlpha() > 0.0_hf || hasBlur());
}
bool EffectLayer::setColor(const half3& color) {
@@ -144,7 +144,7 @@
sp<Layer> EffectLayer::createClone() {
sp<EffectLayer> layer = mFlinger->getFactory().createEffectLayer(
LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()));
- layer->setInitialValuesForClone(this);
+ layer->setInitialValuesForClone(sp<Layer>::fromExisting(this));
return layer;
}
diff --git a/services/surfaceflinger/FpsReporter.cpp b/services/surfaceflinger/FpsReporter.cpp
index c89c9ff..155cf4d 100644
--- a/services/surfaceflinger/FpsReporter.cpp
+++ b/services/surfaceflinger/FpsReporter.cpp
@@ -63,7 +63,8 @@
for (TrackedListener& listener : localListeners) {
if (listener.taskId == taskId) {
seenTasks.insert(taskId);
- listenersAndLayersToReport.push_back({listener, sp<Layer>(layer)});
+ listenersAndLayersToReport.push_back(
+ {listener, sp<Layer>::fromExisting(layer)});
break;
}
}
@@ -90,7 +91,7 @@
void FpsReporter::addListener(const sp<gui::IFpsListener>& listener, int32_t taskId) {
sp<IBinder> asBinder = IInterface::asBinder(listener);
- asBinder->linkToDeath(this);
+ asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
std::lock_guard lock(mMutex);
mListeners.emplace(wp<IBinder>(asBinder), TrackedListener{listener, taskId});
}
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 3e69b5c..c73a75c 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -109,11 +109,11 @@
jankType &= ~JankType::DisplayHAL;
}
if (jankType & JankType::SurfaceFlingerCpuDeadlineMissed) {
- janks.emplace_back("SurfaceFlinger CPU Deadline Missed");
+ janks.emplace_back("SurfaceFlinger deadline missed (while in HWC)");
jankType &= ~JankType::SurfaceFlingerCpuDeadlineMissed;
}
if (jankType & JankType::SurfaceFlingerGpuDeadlineMissed) {
- janks.emplace_back("SurfaceFlinger GPU Deadline Missed");
+ janks.emplace_back("SurfaceFlinger deadline missed (while in GPU comp)");
jankType &= ~JankType::SurfaceFlingerGpuDeadlineMissed;
}
if (jankType & JankType::AppDeadlineMissed) {
@@ -986,11 +986,8 @@
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()) {
- // If SF was in GPU composition and the CPU work finished before the vsync
- // period, classify it as GPU deadline missed.
+ if (mGpuFence != FenceTime::NO_FENCE) {
+ // If SF was in GPU composition, classify it as GPU deadline missed.
mJankType = JankType::SurfaceFlingerGpuDeadlineMissed;
} else {
mJankType = JankType::SurfaceFlingerCpuDeadlineMissed;
diff --git a/services/surfaceflinger/HdrLayerInfoReporter.cpp b/services/surfaceflinger/HdrLayerInfoReporter.cpp
index c06e300..c88554e 100644
--- a/services/surfaceflinger/HdrLayerInfoReporter.cpp
+++ b/services/surfaceflinger/HdrLayerInfoReporter.cpp
@@ -51,7 +51,7 @@
void HdrLayerInfoReporter::addListener(const sp<gui::IHdrLayerInfoListener>& listener) {
sp<IBinder> asBinder = IInterface::asBinder(listener);
- asBinder->linkToDeath(this);
+ asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
std::lock_guard lock(mMutex);
mListeners.emplace(wp<IBinder>(asBinder), TrackedListener{listener, HdrLayerInfo{}});
}
diff --git a/services/surfaceflinger/HwcSlotGenerator.cpp b/services/surfaceflinger/HwcSlotGenerator.cpp
new file mode 100644
index 0000000..939c35b
--- /dev/null
+++ b/services/surfaceflinger/HwcSlotGenerator.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "HwcSlotGenerator"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <gui/BufferQueue.h>
+
+#include "HwcSlotGenerator.h"
+
+namespace android {
+
+HwcSlotGenerator::HwcSlotGenerator() {
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ mFreeHwcCacheSlots.push(i);
+ }
+}
+
+void HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) {
+ std::lock_guard lock(mMutex);
+ if (!clientCacheId.isValid()) {
+ ALOGE("invalid process, failed to erase buffer");
+ return;
+ }
+ eraseBufferLocked(clientCacheId);
+}
+
+int HwcSlotGenerator::getHwcCacheSlot(const client_cache_t& clientCacheId) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ auto itr = mCachedBuffers.find(clientCacheId);
+ if (itr == mCachedBuffers.end()) {
+ return addCachedBuffer(clientCacheId);
+ }
+ auto& [hwcCacheSlot, counter] = itr->second;
+ counter = mCounter++;
+ return hwcCacheSlot;
+}
+
+int HwcSlotGenerator::addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex) {
+ if (!clientCacheId.isValid()) {
+ ALOGE("invalid process, returning invalid slot");
+ return BufferQueue::INVALID_BUFFER_SLOT;
+ }
+
+ ClientCache::getInstance().registerErasedRecipient(clientCacheId,
+ wp<ErasedRecipient>::fromExisting(this));
+
+ int hwcCacheSlot = getFreeHwcCacheSlot();
+ mCachedBuffers[clientCacheId] = {hwcCacheSlot, mCounter++};
+ return hwcCacheSlot;
+}
+
+int HwcSlotGenerator::getFreeHwcCacheSlot() REQUIRES(mMutex) {
+ if (mFreeHwcCacheSlots.empty()) {
+ evictLeastRecentlyUsed();
+ }
+
+ int hwcCacheSlot = mFreeHwcCacheSlots.top();
+ mFreeHwcCacheSlots.pop();
+ return hwcCacheSlot;
+}
+
+void HwcSlotGenerator::evictLeastRecentlyUsed() REQUIRES(mMutex) {
+ uint64_t minCounter = UINT_MAX;
+ client_cache_t minClientCacheId = {};
+ for (const auto& [clientCacheId, slotCounter] : mCachedBuffers) {
+ const auto& [hwcCacheSlot, counter] = slotCounter;
+ if (counter < minCounter) {
+ minCounter = counter;
+ minClientCacheId = clientCacheId;
+ }
+ }
+ eraseBufferLocked(minClientCacheId);
+
+ ClientCache::getInstance().unregisterErasedRecipient(minClientCacheId,
+ wp<ErasedRecipient>::fromExisting(this));
+}
+
+void HwcSlotGenerator::eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex) {
+ auto itr = mCachedBuffers.find(clientCacheId);
+ if (itr == mCachedBuffers.end()) {
+ return;
+ }
+ auto& [hwcCacheSlot, counter] = itr->second;
+
+ // TODO send to hwc cache and resources
+
+ mFreeHwcCacheSlots.push(hwcCacheSlot);
+ mCachedBuffers.erase(clientCacheId);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/HwcSlotGenerator.h b/services/surfaceflinger/HwcSlotGenerator.h
new file mode 100644
index 0000000..5a1b6d7
--- /dev/null
+++ b/services/surfaceflinger/HwcSlotGenerator.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2022 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 <functional>
+#include <mutex>
+#include <stack>
+#include <unordered_map>
+
+#include "ClientCache.h"
+
+namespace android {
+
+class HwcSlotGenerator : public ClientCache::ErasedRecipient {
+public:
+ HwcSlotGenerator();
+ void bufferErased(const client_cache_t& clientCacheId);
+ int getHwcCacheSlot(const client_cache_t& clientCacheId);
+
+private:
+ friend class SlotGenerationTest;
+ int addCachedBuffer(const client_cache_t& clientCacheId) REQUIRES(mMutex);
+ int getFreeHwcCacheSlot() REQUIRES(mMutex);
+ void evictLeastRecentlyUsed() REQUIRES(mMutex);
+ void eraseBufferLocked(const client_cache_t& clientCacheId) REQUIRES(mMutex);
+
+ struct CachedBufferHash {
+ std::size_t operator()(const client_cache_t& clientCacheId) const {
+ return std::hash<uint64_t>{}(clientCacheId.id);
+ }
+ };
+
+ std::mutex mMutex;
+
+ std::unordered_map<client_cache_t, std::pair<int /*HwcCacheSlot*/, uint64_t /*counter*/>,
+ CachedBufferHash>
+ mCachedBuffers GUARDED_BY(mMutex);
+ std::stack<int /*HwcCacheSlot*/> mFreeHwcCacheSlots GUARDED_BY(mMutex);
+
+ // The cache increments this counter value when a slot is updated or used.
+ // Used to track the least recently-used buffer
+ uint64_t mCounter = 0;
+};
+} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ba3cb51..5e1a858 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -78,6 +78,7 @@
namespace android {
namespace {
constexpr int kDumpTableRowLength = 159;
+const ui::Transform kIdentityTransform;
} // namespace
using namespace ftl::flag_operators;
@@ -93,7 +94,7 @@
Layer::Layer(const LayerCreationArgs& args)
: sequence(args.sequence.value_or(sSequence++)),
- mFlinger(args.flinger),
+ mFlinger(sp<SurfaceFlinger>::fromExisting(args.flinger)),
mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)),
mClientRef(args.client),
mWindowType(static_cast<WindowInfo::Type>(
@@ -227,7 +228,7 @@
}
if (!std::binary_search(layersInTree.begin(), layersInTree.end(), strongRelative.get())) {
- strongRelative->removeZOrderRelative(this);
+ strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this));
mFlinger->setTransactionFlags(eTraversalNeeded);
setZOrderRelativeOf(nullptr);
}
@@ -239,13 +240,13 @@
mFlinger->mScheduler->deregisterLayer(this);
}
- mFlinger->markLayerPendingRemovalLocked(this);
+ mFlinger->markLayerPendingRemovalLocked(sp<Layer>::fromExisting(this));
}
sp<Layer> Layer::getRootLayer() {
sp<Layer> parent = getParent();
if (parent == nullptr) {
- return this;
+ return sp<Layer>::fromExisting(this);
}
return parent->getRootLayer();
}
@@ -288,7 +289,7 @@
return nullptr;
}
mGetHandleCalled = true;
- return new Handle(mFlinger, this);
+ return sp<Handle>::make(mFlinger, sp<Layer>::fromExisting(this));
}
// ---------------------------------------------------------------------------
@@ -520,8 +521,9 @@
}
sp<compositionengine::LayerFE> Layer::asLayerFE() const {
- return const_cast<compositionengine::LayerFE*>(
+ compositionengine::LayerFE* layerFE = const_cast<compositionengine::LayerFE*>(
static_cast<const compositionengine::LayerFE*>(this));
+ return sp<compositionengine::LayerFE>::fromExisting(layerFE);
}
sp<compositionengine::LayerFE> Layer::getCompositionEngineLayerFE() const {
@@ -812,7 +814,7 @@
if (mDrawingState.zOrderRelativeOf != nullptr) {
sp<Layer> strongRelative = mDrawingState.zOrderRelativeOf.promote();
if (strongRelative != nullptr) {
- strongRelative->removeZOrderRelative(this);
+ strongRelative->removeZOrderRelative(wp<Layer>::fromExisting(this));
}
setZOrderRelativeOf(nullptr);
}
@@ -870,10 +872,10 @@
auto oldZOrderRelativeOf = mDrawingState.zOrderRelativeOf.promote();
if (oldZOrderRelativeOf != nullptr) {
- oldZOrderRelativeOf->removeZOrderRelative(this);
+ oldZOrderRelativeOf->removeZOrderRelative(wp<Layer>::fromExisting(this));
}
setZOrderRelativeOf(relative);
- relative->addZOrderRelative(this);
+ relative->addZOrderRelative(wp<Layer>::fromExisting(this));
setTransactionFlags(eTransactionNeeded);
@@ -1240,7 +1242,7 @@
void Layer::updateTreeHasFrameRateVote() {
const auto root = [&]() -> sp<Layer> {
- sp<Layer> layer = this;
+ sp<Layer> layer = sp<Layer>::fromExisting(this);
while (auto parent = layer->getParent()) {
layer = parent;
}
@@ -1613,7 +1615,7 @@
setTransactionFlags(eTransactionNeeded);
mCurrentChildren.add(layer);
- layer->setParent(this);
+ layer->setParent(sp<Layer>::fromExisting(this));
layer->setGameModeForTree(mGameMode);
updateTreeHasFrameRateVote();
}
@@ -1658,11 +1660,11 @@
sp<Layer> parent = getParent();
if (parent != nullptr) {
- parent->removeChild(this);
+ parent->removeChild(sp<Layer>::fromExisting(this));
}
if (newParentHandle != nullptr) {
- newParent->addChild(this);
+ newParent->addChild(sp<Layer>::fromExisting(this));
if (!newParent->isRemovedFromCurrentState()) {
addToCurrentState();
} else {
@@ -1944,8 +1946,11 @@
}
int32_t Layer::getBackgroundBlurRadius() const {
- const auto& p = mDrawingParent.promote();
+ if (getDrawingState().backgroundBlurRadius == 0) {
+ return 0;
+ }
+ const auto& p = mDrawingParent.promote();
half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
return parentAlpha * getDrawingState().backgroundBlurRadius;
}
@@ -2060,7 +2065,7 @@
zOrderRelativeOf->mName.c_str());
ALOGE("Severing rel Z loop, potentially dangerous");
mDrawingState.isRelativeOf = false;
- zOrderRelativeOf->removeZOrderRelative(this);
+ zOrderRelativeOf->removeZOrderRelative(wp<Layer>::fromExisting(this));
}
}
}
@@ -2112,8 +2117,6 @@
layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace())));
layerInfo->set_queued_frames(getQueuedFrameCount());
layerInfo->set_curr_frame(mCurrentFrameNumber);
- layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
-
layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius);
layerInfo->set_corner_radius(
(getRoundedCornerState().radius.x + getRoundedCornerState().radius.y) / 2.0);
@@ -2209,7 +2212,8 @@
if ((traceFlags & LayerTracing::TRACE_INPUT) && needsInputInfo()) {
WindowInfo info;
if (useDrawing) {
- info = fillInputInfo(ui::Transform(), /* displayIsSecure */ true);
+ info = fillInputInfo(
+ InputDisplayArgs{.transform = &kIdentityTransform, .isSecure = true});
} else {
info = state.inputInfo;
}
@@ -2339,7 +2343,7 @@
}
void Layer::fillTouchOcclusionMode(WindowInfo& info) {
- sp<Layer> p = this;
+ sp<Layer> p = sp<Layer>::fromExisting(this);
while (p != nullptr && !p->hasInputInfo()) {
p = p->mDrawingParent.promote();
}
@@ -2416,7 +2420,7 @@
}
}
-WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool displayIsSecure) {
+WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) {
if (!hasInputInfo()) {
mDrawingState.inputInfo.name = getName();
mDrawingState.inputInfo.ownerUid = mOwnerUid;
@@ -2425,12 +2429,21 @@
mDrawingState.inputInfo.displayId = getLayerStack().id;
}
+ const ui::Transform& displayTransform =
+ displayArgs.transform != nullptr ? *displayArgs.transform : kIdentityTransform;
+
WindowInfo info = mDrawingState.inputInfo;
info.id = sequence;
info.displayId = getLayerStack().id;
fillInputFrameInfo(info, displayTransform);
+ if (displayArgs.transform == nullptr) {
+ // Do not let the window receive touches if it is not associated with a valid display
+ // transform. We still allow the window to receive keys and prevent ANRs.
+ info.inputConfig |= WindowInfo::InputConfig::NOT_TOUCHABLE;
+ }
+
// For compatibility reasons we let layers which can receive input
// receive input before they have actually submitted a buffer. Because
// of this we use canReceiveInput instead of isVisible to check the
@@ -2448,7 +2461,7 @@
// If the window will be blacked out on a display because the display does not have the secure
// flag and the layer has the secure flag set, then drop input.
- if (!displayIsSecure && isSecure()) {
+ if (!displayArgs.isSecure && isSecure()) {
info.inputConfig |= WindowInfo::InputConfig::DROP_INPUT;
}
@@ -2482,7 +2495,7 @@
sp<Layer> Layer::getClonedRoot() {
if (mClonedChild != nullptr) {
- return this;
+ return sp<Layer>::fromExisting(this);
}
if (mDrawingParent == nullptr || mDrawingParent.promote() == nullptr) {
return nullptr;
@@ -2536,7 +2549,7 @@
}
mClonedChild->updateClonedDrawingState(clonedLayersMap);
- mClonedChild->updateClonedChildren(this, clonedLayersMap);
+ mClonedChild->updateClonedChildren(sp<Layer>::fromExisting(this), clonedLayersMap);
mClonedChild->updateClonedRelatives(clonedLayersMap);
}
@@ -2547,7 +2560,7 @@
if (isClonedFromAlive()) {
sp<Layer> clonedFrom = getClonedFrom();
cloneDrawingState(clonedFrom.get());
- clonedLayersMap.emplace(clonedFrom, this);
+ clonedLayersMap.emplace(clonedFrom, sp<Layer>::fromExisting(this));
}
// The clone layer may have children in drawingState since they may have been created and
@@ -2591,7 +2604,7 @@
if (clonedLayersMap.count(cropLayer) == 0) {
// Real layer had a crop layer but it's not in the cloned hierarchy. Just set to
// self as crop layer to avoid going outside bounds.
- mDrawingState.touchableRegionCrop = this;
+ mDrawingState.touchableRegionCrop = wp<Layer>::fromExisting(this);
} else {
const sp<Layer>& clonedCropLayer = clonedLayersMap.at(cropLayer);
mDrawingState.touchableRegionCrop = clonedCropLayer;
@@ -2603,7 +2616,7 @@
}
void Layer::updateClonedRelatives(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
- mDrawingState.zOrderRelativeOf = nullptr;
+ mDrawingState.zOrderRelativeOf = wp<Layer>();
mDrawingState.zOrderRelatives.clear();
if (!isClonedFromAlive()) {
@@ -2639,7 +2652,7 @@
void Layer::addChildToDrawing(const sp<Layer>& layer) {
mDrawingChildren.add(layer);
- layer->mDrawingParent = this;
+ layer->mDrawingParent = sp<Layer>::fromExisting(this);
}
Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t compatibility) {
@@ -2701,7 +2714,7 @@
}
// We can safely cast this binder since its local and we verified its interface descriptor.
- sp<Handle> handle = static_cast<Handle*>(handleBinder.get());
+ sp<Handle> handle = sp<Handle>::cast(handleBinder);
return handle->owner;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b809c8a..22bb866 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -528,8 +528,6 @@
virtual bool isHdrY410() const { return false; }
- virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
-
/*
* called after composition.
* returns true if the layer latched a new buffer this frame.
@@ -542,17 +540,13 @@
// If a buffer was replaced this frame, release the former buffer
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
- virtual void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
- const CompositorTiming& /*compositorTiming*/) {}
-
/*
* latchBuffer - called each time the screen is redrawn and returns whether
* the visible regions need to be recomputed (this is a fairly heavy
* operation, so this should be set only if needed). Typically this is used
* to figure out if the content or size of a surface has changed.
*/
- virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
- nsecs_t /*expectedPresentTime*/) {
+ virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) {
return false;
}
@@ -854,7 +848,11 @@
bool getPremultipledAlpha() const;
void setInputInfo(const gui::WindowInfo& info);
- gui::WindowInfo fillInputInfo(const ui::Transform& displayTransform, bool displayIsSecure);
+ struct InputDisplayArgs {
+ const ui::Transform* transform = nullptr;
+ bool isSecure = false;
+ };
+ gui::WindowInfo fillInputInfo(const InputDisplayArgs& displayArgs);
/**
* Returns whether this layer has an explicitly set input-info.
@@ -926,11 +924,6 @@
virtual void commitTransaction(State& stateToCommit);
virtual void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&) {}
- // Returns mCurrentScaling mode (originating from the
- // Client) or mOverrideScalingMode mode (originating from
- // the Surface Controller) if set.
- virtual uint32_t getEffectiveScalingMode() const { return 0; }
-
sp<compositionengine::LayerFE> asLayerFE() const;
sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; }
bool isClone() { return mClonedFrom != nullptr; }
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index 896f254..e17b01f 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -17,8 +17,8 @@
#include <ui/GraphicTypes.h>
#include <ui/Transform.h>
-#include "ContainerLayer.h"
#include "DisplayDevice.h"
+#include "EffectLayer.h"
#include "Layer.h"
#include "LayerRenderArea.h"
#include "SurfaceFlinger.h"
@@ -110,8 +110,9 @@
// layer which has no properties set and which does not draw.
// We hold the statelock as the reparent-for-drawing operation modifies the
// hierarchy and there could be readers on Binder threads, like dump.
- sp<ContainerLayer> screenshotParentLayer = mFlinger.getFactory().createContainerLayer(
- {&mFlinger, nullptr, "Screenshot Parent"s, 0, LayerMetadata()});
+ sp<EffectLayer> screenshotParentLayer = mFlinger.getFactory().createEffectLayer(
+ {&mFlinger, nullptr, "Screenshot Parent"s, ISurfaceComposerClient::eNoColorFill,
+ LayerMetadata()});
{
Mutex::Autolock _l(mFlinger.mStateLock);
reparentForDrawing(mLayer, screenshotParentLayer, sourceCrop);
diff --git a/services/surfaceflinger/LocklessQueue.h b/services/surfaceflinger/LocklessQueue.h
new file mode 100644
index 0000000..6b63360
--- /dev/null
+++ b/services/surfaceflinger/LocklessQueue.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2022 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 <atomic>
+#include <optional>
+
+template <typename T>
+// Single consumer multi producer stack. We can understand the two operations independently to see
+// why they are without race condition.
+//
+// push is responsible for maintaining a linked list stored in mPush, and called from multiple
+// threads without lock. We can see that if two threads never observe the same value from
+// mPush.load, it just functions as a normal linked list. In the case where two threads observe the
+// same value, one of them has to execute the compare_exchange first. The one that doesn't execute
+// the compare exchange first, will receive false from compare_exchange. previousHead is updated (by
+// compare_exchange) to the most recent value of mPush, and we try again. It's relatively clear to
+// see that the process can repeat with an arbitrary number of threads.
+//
+// Pop is much simpler. If mPop is empty (as it begins) it atomically exchanges
+// the entire push list with null. This is safe, since the only other reader (push)
+// of mPush will retry if it changes in between it's read and atomic compare. We
+// then store the list and pop one element.
+//
+// If we already had something in the pop list we just pop directly.
+class LocklessQueue {
+public:
+ class Entry {
+ public:
+ T mValue;
+ std::atomic<Entry*> mNext;
+ Entry(T value) : mValue(value) {}
+ };
+ std::atomic<Entry*> mPush = nullptr;
+ std::atomic<Entry*> mPop = nullptr;
+ bool isEmpty() { return (mPush.load() == nullptr) && (mPop.load() == nullptr); }
+
+ void push(T value) {
+ Entry* entry = new Entry(value);
+ Entry* previousHead = mPush.load(/*std::memory_order_relaxed*/);
+ do {
+ entry->mNext = previousHead;
+ } while (!mPush.compare_exchange_weak(previousHead, entry)); /*std::memory_order_release*/
+ }
+ std::optional<T> pop() {
+ Entry* popped = mPop.load(/*std::memory_order_acquire*/);
+ if (popped) {
+ // Single consumer so this is fine
+ mPop.store(popped->mNext /* , std::memory_order_release */);
+ auto value = popped->mValue;
+ delete popped;
+ return std::move(value);
+ } else {
+ Entry* grabbedList = mPush.exchange(nullptr /* , std::memory_order_acquire */);
+ if (!grabbedList) return std::nullopt;
+ // Reverse the list
+ while (grabbedList->mNext) {
+ Entry* next = grabbedList->mNext;
+ grabbedList->mNext = popped;
+ popped = grabbedList;
+ grabbedList = next;
+ }
+ mPop.store(popped /* , std::memory_order_release */);
+ auto value = grabbedList->mValue;
+ delete grabbedList;
+ return std::move(value);
+ }
+ }
+};
diff --git a/services/surfaceflinger/NativeWindowSurface.cpp b/services/surfaceflinger/NativeWindowSurface.cpp
index 3fff928..a6a3eec 100644
--- a/services/surfaceflinger/NativeWindowSurface.cpp
+++ b/services/surfaceflinger/NativeWindowSurface.cpp
@@ -30,7 +30,7 @@
class NativeWindowSurface final : public surfaceflinger::NativeWindowSurface {
public:
explicit NativeWindowSurface(const sp<IGraphicBufferProducer>& producer)
- : mSurface(new Surface(producer, /* controlledByApp */ false)) {}
+ : mSurface(sp<Surface>::make(producer, /* controlledByApp */ false)) {}
~NativeWindowSurface() override = default;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index a9180d4..9b19afb 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -152,13 +152,13 @@
}
}();
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(static_cast<uint32_t>(bufferWidth),
- static_cast<uint32_t>(bufferHeight), HAL_PIXEL_FORMAT_RGBA_8888,
- 1,
- GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
- GRALLOC_USAGE_HW_TEXTURE,
- "RefreshRateOverlayBuffer");
+ const auto kUsageFlags =
+ static_cast<uint64_t>(GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER |
+ GRALLOC_USAGE_HW_TEXTURE);
+ sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth),
+ static_cast<uint32_t>(bufferHeight),
+ HAL_PIXEL_FORMAT_RGBA_8888, 1u,
+ kUsageFlags, "RefreshRateOverlayBuffer");
const status_t bufferStatus = buffer->initCheck();
LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d",
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 2487dbd..5705255 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -132,7 +132,7 @@
void RegionSamplingThread::addListener(const Rect& samplingArea, const wp<Layer>& stopLayer,
const sp<IRegionSamplingListener>& listener) {
sp<IBinder> asBinder = IInterface::asBinder(listener);
- asBinder->linkToDeath(this);
+ asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
std::lock_guard lock(mSamplingMutex);
mDescriptors.emplace(wp<IBinder>(asBinder), Descriptor{samplingArea, stopLayer, listener});
}
@@ -344,8 +344,8 @@
const uint32_t usage =
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
sp<GraphicBuffer> graphicBuffer =
- new GraphicBuffer(sampledBounds.getWidth(), sampledBounds.getHeight(),
- PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
+ sp<GraphicBuffer>::make(sampledBounds.getWidth(), sampledBounds.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 1, usage, "RegionSamplingThread");
const status_t bufferStatus = graphicBuffer->initCheck();
LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureSample: Buffer failed to allocate: %d",
bufferStatus);
diff --git a/services/surfaceflinger/Scheduler/Android.bp b/services/surfaceflinger/Scheduler/Android.bp
index 5de796d..5bd8a99 100644
--- a/services/surfaceflinger/Scheduler/Android.bp
+++ b/services/surfaceflinger/Scheduler/Android.bp
@@ -18,6 +18,7 @@
"libbase",
"libcutils",
"liblog",
+ "libui",
"libutils",
],
}
@@ -39,6 +40,7 @@
name: "libscheduler",
defaults: ["libscheduler_defaults"],
srcs: [
+ "src/PresentLatencyTracker.cpp",
"src/Timer.cpp",
],
local_include_dirs: ["include"],
@@ -50,6 +52,7 @@
test_suites: ["device-tests"],
defaults: ["libscheduler_defaults"],
srcs: [
+ "tests/PresentLatencyTrackerTest.cpp",
"tests/TimerTest.cpp",
],
static_libs: [
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index d152ab2..d3f53c1 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -173,7 +173,7 @@
void EventThreadConnection::onFirstRef() {
// NOTE: mEventThread doesn't hold a strong reference on us
- mEventThread->registerDisplayEventConnection(this);
+ mEventThread->registerDisplayEventConnection(sp<EventThreadConnection>::fromExisting(this));
}
binder::Status EventThreadConnection::stealReceiveChannel(gui::BitTube* outChannel) {
@@ -188,20 +188,22 @@
}
binder::Status EventThreadConnection::setVsyncRate(int rate) {
- mEventThread->setVsyncRate(static_cast<uint32_t>(rate), this);
+ mEventThread->setVsyncRate(static_cast<uint32_t>(rate),
+ sp<EventThreadConnection>::fromExisting(this));
return binder::Status::ok();
}
binder::Status EventThreadConnection::requestNextVsync() {
ATRACE_CALL();
- mEventThread->requestNextVsync(this);
+ mEventThread->requestNextVsync(sp<EventThreadConnection>::fromExisting(this));
return binder::Status::ok();
}
binder::Status EventThreadConnection::getLatestVsyncEventData(
ParcelableVsyncEventData* outVsyncEventData) {
ATRACE_CALL();
- outVsyncEventData->vsync = mEventThread->getLatestVsyncEventData(this);
+ outVsyncEventData->vsync =
+ mEventThread->getLatestVsyncEventData(sp<EventThreadConnection>::fromExisting(this));
return binder::Status::ok();
}
@@ -289,9 +291,9 @@
sp<EventThreadConnection> EventThread::createEventConnection(
ResyncCallback resyncCallback, EventRegistrationFlags eventRegistration) const {
- return new EventThreadConnection(const_cast<EventThread*>(this),
- IPCThreadState::self()->getCallingUid(),
- std::move(resyncCallback), eventRegistration);
+ return sp<EventThreadConnection>::make(const_cast<EventThread*>(this),
+ IPCThreadState::self()->getCallingUid(),
+ std::move(resyncCallback), eventRegistration);
}
status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index f2af85e..e1ac301 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -30,11 +30,11 @@
namespace android::impl {
-void MessageQueue::Handler::dispatchFrame(int64_t vsyncId, nsecs_t expectedVsyncTime) {
+void MessageQueue::Handler::dispatchFrame(VsyncId vsyncId, TimePoint expectedVsyncTime) {
if (!mFramePending.exchange(true)) {
mVsyncId = vsyncId;
mExpectedVsyncTime = expectedVsyncTime;
- mQueue.mLooper->sendMessage(this, Message());
+ mQueue.mLooper->sendMessage(sp<MessageHandler>::fromExisting(this), Message());
}
}
@@ -44,16 +44,7 @@
void MessageQueue::Handler::handleMessage(const Message&) {
mFramePending.store(false);
-
- const nsecs_t frameTime = systemTime();
- auto& compositor = mQueue.mCompositor;
-
- if (!compositor.commit(frameTime, mVsyncId, mExpectedVsyncTime)) {
- return;
- }
-
- compositor.composite(frameTime, mVsyncId);
- compositor.sample();
+ mQueue.onFrameSignal(mQueue.mCompositor, mVsyncId, mExpectedVsyncTime);
}
MessageQueue::MessageQueue(ICompositor& compositor)
@@ -102,16 +93,17 @@
// Trace VSYNC-sf
mVsync.value = (mVsync.value + 1) % 2;
+ const auto expectedVsyncTime = TimePoint::fromNs(vsyncTime);
{
std::lock_guard lock(mVsync.mutex);
- mVsync.lastCallbackTime = std::chrono::nanoseconds(vsyncTime);
+ mVsync.lastCallbackTime = expectedVsyncTime;
mVsync.scheduledFrameTime.reset();
}
- const auto vsyncId = mVsync.tokenManager->generateTokenForPredictions(
- {targetWakeupTime, readyTime, vsyncTime});
+ const auto vsyncId = VsyncId{mVsync.tokenManager->generateTokenForPredictions(
+ {targetWakeupTime, readyTime, vsyncTime})};
- mHandler->dispatchFrame(vsyncId, vsyncTime);
+ mHandler->dispatchFrame(vsyncId, expectedVsyncTime);
}
void MessageQueue::initVsync(scheduler::VSyncDispatch& dispatch,
@@ -133,9 +125,10 @@
std::lock_guard lock(mVsync.mutex);
mVsync.workDuration = workDuration;
if (mVsync.scheduledFrameTime) {
- mVsync.scheduledFrameTime = mVsync.registration->schedule(
- {mVsync.workDuration.get().count(),
- /*readyDuration=*/0, mVsync.lastCallbackTime.count()});
+ mVsync.scheduledFrameTime =
+ mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
+ .readyDuration = 0,
+ .earliestVsync = mVsync.lastCallbackTime.ns()});
}
}
@@ -171,7 +164,7 @@
{
std::lock_guard lock(mInjector.mutex);
if (CC_UNLIKELY(mInjector.connection)) {
- ALOGD("%s while injecting VSYNC", __FUNCTION__);
+ ALOGD("%s while injecting VSYNC", __func__);
mInjector.connection->requestNextVsync();
return;
}
@@ -181,7 +174,7 @@
mVsync.scheduledFrameTime =
mVsync.registration->schedule({.workDuration = mVsync.workDuration.get().count(),
.readyDuration = 0,
- .earliestVsync = mVsync.lastCallbackTime.count()});
+ .earliestVsync = mVsync.lastCallbackTime.ns()});
}
void MessageQueue::injectorCallback() {
@@ -190,9 +183,10 @@
while ((n = DisplayEventReceiver::getEvents(&mInjector.tube, buffer, 8)) > 0) {
for (int i = 0; i < n; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
- auto& vsync = buffer[i].vsync;
- mHandler->dispatchFrame(vsync.vsyncData.preferredVsyncId(),
- vsync.vsyncData.preferredExpectedPresentationTime());
+ auto& vsync = buffer[i].vsync.vsyncData;
+ mHandler->dispatchFrame(VsyncId{vsync.preferredVsyncId()},
+ TimePoint::fromNs(
+ vsync.preferredExpectedPresentationTime()));
break;
}
}
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 4082e26..506f27b 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -25,8 +25,12 @@
#include <android/gui/IDisplayEventConnection.h>
#include <private/gui/BitTube.h>
#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
#include <utils/Timers.h>
+#include <scheduler/Time.h>
+#include <scheduler/VsyncId.h>
+
#include "EventThread.h"
#include "TracedOrdinal.h"
#include "VSyncDispatch.h"
@@ -34,8 +38,8 @@
namespace android {
struct ICompositor {
- virtual bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) = 0;
- virtual void composite(nsecs_t frameTime, int64_t vsyncId) = 0;
+ virtual bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) = 0;
+ virtual void composite(TimePoint frameTime, VsyncId) = 0;
virtual void sample() = 0;
protected:
@@ -47,6 +51,9 @@
template <typename G>
friend auto makeTask(G&&);
+ template <typename... Args>
+ friend sp<Task<F>> sp<Task<F>>::make(Args&&... args);
+
explicit Task(F&& f) : mTask(std::move(f)) {}
void handleMessage(const Message&) override { mTask(); }
@@ -57,7 +64,7 @@
template <typename F>
inline auto makeTask(F&& f) {
- sp<Task<F>> task = new Task<F>(std::move(f));
+ sp<Task<F>> task = sp<Task<F>>::make(std::forward<F>(f));
return std::make_pair(task, task->mTask.get_future());
}
@@ -84,8 +91,9 @@
class Handler : public MessageHandler {
MessageQueue& mQueue;
std::atomic_bool mFramePending = false;
- std::atomic<int64_t> mVsyncId = 0;
- std::atomic<nsecs_t> mExpectedVsyncTime = 0;
+
+ std::atomic<VsyncId> mVsyncId;
+ std::atomic<TimePoint> mExpectedVsyncTime;
public:
explicit Handler(MessageQueue& queue) : mQueue(queue) {}
@@ -93,7 +101,7 @@
bool isFramePending() const;
- virtual void dispatchFrame(int64_t vsyncId, nsecs_t expectedVsyncTime);
+ virtual void dispatchFrame(VsyncId, TimePoint expectedVsyncTime);
};
friend class Handler;
@@ -104,6 +112,8 @@
void vsyncCallback(nsecs_t vsyncTime, nsecs_t targetWakeupTime, nsecs_t readyTime);
private:
+ virtual void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) = 0;
+
ICompositor& mCompositor;
const sp<Looper> mLooper;
const sp<Handler> mHandler;
@@ -115,7 +125,7 @@
mutable std::mutex mutex;
TracedOrdinal<std::chrono::nanoseconds> workDuration
GUARDED_BY(mutex) = {"VsyncWorkDuration-sf", std::chrono::nanoseconds(0)};
- std::chrono::nanoseconds lastCallbackTime GUARDED_BY(mutex) = std::chrono::nanoseconds{0};
+ TimePoint lastCallbackTime GUARDED_BY(mutex);
std::optional<nsecs_t> scheduledFrameTime GUARDED_BY(mutex);
TracedOrdinal<int> value = {"VSYNC-sf", 0};
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index a3d4e8d..55ae013 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -131,6 +131,18 @@
}
}
+void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
+ TimePoint expectedVsyncTime) {
+ const TimePoint frameTime = SchedulerClock::now();
+
+ if (!compositor.commit(frameTime, vsyncId, expectedVsyncTime)) {
+ return;
+ }
+
+ compositor.composite(frameTime, vsyncId);
+ compositor.sample();
+}
+
void Scheduler::createVsyncSchedule(FeatureFlags features) {
mVsyncSchedule.emplace(features);
}
@@ -151,20 +163,20 @@
.getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent);
}
-bool Scheduler::isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const {
+bool Scheduler::isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const {
const auto frameRate = getFrameRateOverride(uid);
if (!frameRate.has_value()) {
return true;
}
- return mVsyncSchedule->getTracker().isVSyncInPhase(expectedVsyncTimestamp, *frameRate);
+ return mVsyncSchedule->getTracker().isVSyncInPhase(expectedVsyncTimestamp.ns(), *frameRate);
}
impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const {
std::scoped_lock lock(mRefreshRateConfigsLock);
return [this](nsecs_t expectedVsyncTimestamp, uid_t uid) {
- return !isVsyncValid(expectedVsyncTimestamp, uid);
+ return !isVsyncValid(TimePoint::fromNs(expectedVsyncTimestamp), uid);
};
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index f800eeb..4730493 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -192,7 +192,7 @@
// Returns true if a given vsync timestamp is considered valid vsync
// for a given uid
- bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const;
+ bool isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const;
void dump(std::string&) const;
void dump(ConnectionHandle, std::string&) const;
@@ -243,6 +243,9 @@
enum class TimerState { Reset, Expired };
enum class TouchState { Inactive, Active };
+ // impl::MessageQueue overrides:
+ void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override;
+
// Create a connection on the given EventThread.
ConnectionHandle createConnection(std::unique_ptr<EventThread>);
sp<EventThreadConnection> createConnectionInternal(
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index 27f4311..cc9f7cf 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -100,14 +100,8 @@
return getExpectedCallbackTime(nextVsyncTime, timing);
}
- bool const alreadyDispatchedForVsync = mLastDispatchTime &&
- ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
- (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
- if (alreadyDispatchedForVsync) {
- nextVsyncTime =
- tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
- nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
- }
+ nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
+ nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
mScheduleTiming = timing;
@@ -123,6 +117,25 @@
return mWorkloadUpdateInfo.has_value();
}
+nsecs_t VSyncDispatchTimerQueueEntry::adjustVsyncIfNeeded(VSyncTracker& tracker,
+ nsecs_t nextVsyncTime) const {
+ bool const alreadyDispatchedForVsync = mLastDispatchTime &&
+ ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
+ (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
+ const nsecs_t currentPeriod = tracker.currentPeriod();
+ bool const nextVsyncTooClose = mLastDispatchTime &&
+ (nextVsyncTime - *mLastDispatchTime + mMinVsyncDistance) <= currentPeriod;
+ if (alreadyDispatchedForVsync) {
+ return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
+ }
+
+ if (nextVsyncTooClose) {
+ return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod);
+ }
+
+ return nextVsyncTime;
+}
+
void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
if (!mArmedInfo && !mWorkloadUpdateInfo) {
return;
@@ -136,7 +149,9 @@
const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration;
const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.earliestVsync);
- const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(earliestVsync);
+ const auto nextVsyncTime =
+ adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/
+ tracker.nextAnticipatedVSyncTimeFrom(earliestVsync));
const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration;
const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration;
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 4923031..4f2f87a 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -84,6 +84,8 @@
void dump(std::string& result) const;
private:
+ nsecs_t adjustVsyncIfNeeded(VSyncTracker& tracker, nsecs_t nextVsyncTime) const;
+
const std::string mName;
const VSyncDispatch::Callback mCallback;
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 77782e9..898e865 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -167,7 +167,9 @@
vsyncTS[i] = timestamp;
meanTS += timestamp;
- const auto ordinal = (vsyncTS[i] + currentPeriod / 2) / currentPeriod * kScalingFactor;
+ const auto ordinal = currentPeriod == 0
+ ? 0
+ : (vsyncTS[i] + currentPeriod / 2) / currentPeriod * kScalingFactor;
ordinals[i] = ordinal;
meanOrdinal += ordinal;
}
diff --git a/services/surfaceflinger/Scheduler/VsyncModulator.cpp b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
index be57b2a..138d8d6 100644
--- a/services/surfaceflinger/Scheduler/VsyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VsyncModulator.cpp
@@ -53,14 +53,14 @@
case Schedule::EarlyStart:
if (token) {
mEarlyWakeupRequests.emplace(token);
- token->linkToDeath(this);
+ token->linkToDeath(sp<DeathRecipient>::fromExisting(this));
} else {
ALOGW("%s: EarlyStart requested without a valid token", __func__);
}
break;
case Schedule::EarlyEnd: {
if (token && mEarlyWakeupRequests.erase(token) > 0) {
- token->unlinkToDeath(this);
+ token->unlinkToDeath(sp<DeathRecipient>::fromExisting(this));
} else {
ALOGW("%s: Unexpected EarlyEnd", __func__);
}
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/PresentLatencyTracker.h b/services/surfaceflinger/Scheduler/include/scheduler/PresentLatencyTracker.h
new file mode 100644
index 0000000..23ae83f
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/PresentLatencyTracker.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022 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 <memory>
+#include <queue>
+#include <utility>
+
+#include <scheduler/Time.h>
+
+namespace android {
+
+class FenceTime;
+
+namespace scheduler {
+
+// Computes composite-to-present latency by tracking recently composited frames pending to present.
+class PresentLatencyTracker {
+public:
+ // For tests.
+ static constexpr size_t kMaxPendingFrames = 4;
+
+ // Returns the present latency of the latest frame.
+ Duration trackPendingFrame(TimePoint compositeTime,
+ std::shared_ptr<FenceTime> presentFenceTime);
+
+private:
+ struct PendingFrame {
+ PendingFrame(TimePoint compositeTime, std::shared_ptr<FenceTime> presentFenceTime)
+ : compositeTime(compositeTime), presentFenceTime(std::move(presentFenceTime)) {}
+
+ const TimePoint compositeTime;
+ const std::shared_ptr<FenceTime> presentFenceTime;
+ };
+
+ std::queue<PendingFrame> mPendingFrames;
+};
+
+} // namespace scheduler
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Time.h b/services/surfaceflinger/Scheduler/include/scheduler/Time.h
index 6fa548e..f00d456 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/Time.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Time.h
@@ -32,31 +32,33 @@
struct Duration;
struct TimePoint : scheduler::SchedulerClock::time_point {
- explicit TimePoint(const Duration&);
+ constexpr TimePoint() = default;
+ explicit constexpr TimePoint(const Duration&);
// Implicit conversion from std::chrono counterpart.
constexpr TimePoint(scheduler::SchedulerClock::time_point p)
: scheduler::SchedulerClock::time_point(p) {}
- static TimePoint fromNs(nsecs_t);
+ static constexpr TimePoint fromNs(nsecs_t);
nsecs_t ns() const;
};
struct Duration : TimePoint::duration {
// Implicit conversion from std::chrono counterpart.
- constexpr Duration(TimePoint::duration d) : TimePoint::duration(d) {}
+ template <typename R, typename P>
+ constexpr Duration(std::chrono::duration<R, P> d) : TimePoint::duration(d) {}
- static Duration fromNs(nsecs_t ns) { return {std::chrono::nanoseconds(ns)}; }
+ static constexpr Duration fromNs(nsecs_t ns) { return {std::chrono::nanoseconds(ns)}; }
nsecs_t ns() const { return std::chrono::nanoseconds(*this).count(); }
};
using Period = Duration;
-inline TimePoint::TimePoint(const Duration& d) : scheduler::SchedulerClock::time_point(d) {}
+constexpr TimePoint::TimePoint(const Duration& d) : scheduler::SchedulerClock::time_point(d) {}
-inline TimePoint TimePoint::fromNs(nsecs_t ns) {
+constexpr TimePoint TimePoint::fromNs(nsecs_t ns) {
return TimePoint(Duration::fromNs(ns));
}
@@ -64,4 +66,15 @@
return Duration(time_since_epoch()).ns();
}
+// Shorthand to convert the tick count of a Duration to Period and Rep. For example:
+//
+// const auto i = ticks<std::ratio<1>>(d); // Integer seconds.
+// const auto f = ticks<std::milli, float>(d); // Floating-point milliseconds.
+//
+template <typename Period, typename Rep = Duration::rep>
+constexpr Rep ticks(Duration d) {
+ using D = std::chrono::duration<Rep, Period>;
+ return std::chrono::duration_cast<D>(d).count();
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/VsyncId.h b/services/surfaceflinger/Scheduler/include/scheduler/VsyncId.h
new file mode 100644
index 0000000..c64a3cd
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/VsyncId.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 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 <cstdint>
+
+namespace android {
+
+// TODO(b/185536303): Import StrongTyping.h into FTL so it can be used here.
+
+// Sequential frame identifier, also known as FrameTimeline token.
+struct VsyncId {
+ int64_t value = -1;
+};
+
+inline bool operator==(VsyncId lhs, VsyncId rhs) {
+ return lhs.value == rhs.value;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/src/PresentLatencyTracker.cpp b/services/surfaceflinger/Scheduler/src/PresentLatencyTracker.cpp
new file mode 100644
index 0000000..8f3e081
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/src/PresentLatencyTracker.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2022 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 <scheduler/PresentLatencyTracker.h>
+
+#include <cutils/compiler.h>
+#include <log/log.h>
+#include <ui/FenceTime.h>
+
+namespace android::scheduler {
+
+Duration PresentLatencyTracker::trackPendingFrame(TimePoint compositeTime,
+ std::shared_ptr<FenceTime> presentFenceTime) {
+ Duration presentLatency = Duration::zero();
+ while (!mPendingFrames.empty()) {
+ const auto& pendingFrame = mPendingFrames.front();
+ const auto presentTime =
+ TimePoint::fromNs(pendingFrame.presentFenceTime->getCachedSignalTime());
+
+ if (presentTime == TimePoint::fromNs(Fence::SIGNAL_TIME_PENDING)) {
+ break;
+ }
+
+ if (presentTime == TimePoint::fromNs(Fence::SIGNAL_TIME_INVALID)) {
+ ALOGE("%s: Invalid present fence", __func__);
+ } else {
+ presentLatency = presentTime - pendingFrame.compositeTime;
+ }
+
+ mPendingFrames.pop();
+ }
+
+ mPendingFrames.emplace(compositeTime, std::move(presentFenceTime));
+
+ if (CC_UNLIKELY(mPendingFrames.size() > kMaxPendingFrames)) {
+ ALOGE("%s: Too many pending frames", __func__);
+ mPendingFrames.pop();
+ }
+
+ return presentLatency;
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp b/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp
new file mode 100644
index 0000000..8952ca9
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <array>
+
+#include <scheduler/PresentLatencyTracker.h>
+#include <ui/FenceTime.h>
+
+namespace android::scheduler {
+namespace {
+
+using FencePair = std::pair<sp<Fence>, std::shared_ptr<FenceTime>>;
+
+FencePair makePendingFence(FenceToFenceTimeMap& fenceMap) {
+ const auto fence = sp<Fence>::make();
+ return {fence, fenceMap.createFenceTimeForTest(fence)};
+}
+
+} // namespace
+
+TEST(PresentLatencyTrackerTest, skipsInvalidFences) {
+ PresentLatencyTracker tracker;
+
+ const TimePoint kCompositeTime = TimePoint::fromNs(999);
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero());
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero());
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero());
+
+ FenceToFenceTimeMap fenceMap;
+ const auto [fence, fenceTime] = makePendingFence(fenceMap);
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fenceTime), Duration::zero());
+
+ fenceTime->signalForTest(9999);
+
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE),
+ Duration::fromNs(9000));
+}
+
+TEST(PresentLatencyTrackerTest, tracksPendingFrames) {
+ PresentLatencyTracker tracker;
+
+ FenceToFenceTimeMap fenceMap;
+ std::array<FencePair, PresentLatencyTracker::kMaxPendingFrames> fences;
+ std::generate(fences.begin(), fences.end(), [&fenceMap] { return makePendingFence(fenceMap); });
+
+ // The present latency is 0 if all fences are pending.
+ const TimePoint kCompositeTime = TimePoint::fromNs(1234);
+ for (const auto& [fence, fenceTime] : fences) {
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fenceTime), Duration::zero());
+ }
+
+ // If multiple frames have been presented...
+ constexpr size_t kPresentCount = fences.size() / 2;
+ for (size_t i = 0; i < kPresentCount; i++) {
+ fences[i].second->signalForTest(kCompositeTime.ns() + static_cast<nsecs_t>(i));
+ }
+
+ const auto fence = makePendingFence(fenceMap);
+
+ // ...then the present latency is measured using the latest frame.
+ constexpr Duration kPresentLatency = Duration::fromNs(static_cast<nsecs_t>(kPresentCount) - 1);
+ EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fence.second), kPresentLatency);
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4f54f17..db551d7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -108,7 +108,6 @@
#include "BufferStateLayer.h"
#include "Client.h"
#include "Colorizer.h"
-#include "ContainerLayer.h"
#include "DisplayDevice.h"
#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/FramebufferSurface.h"
@@ -159,6 +158,7 @@
namespace android {
+using namespace std::chrono_literals;
using namespace std::string_literals;
using namespace hardware::configstore;
@@ -335,7 +335,7 @@
mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)),
mCompositionEngine(mFactory.createCompositionEngine()),
mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
- mTunnelModeEnabledReporter(new TunnelModeEnabledReporter()),
+ mTunnelModeEnabledReporter(sp<TunnelModeEnabledReporter>::make()),
mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)),
@@ -460,14 +460,14 @@
}
LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
- if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) {
- return LatchUnsignaledConfig::Always;
- }
-
if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, true)) {
return LatchUnsignaledConfig::AutoSingleLayer;
}
+ if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) {
+ return LatchUnsignaledConfig::Always;
+ }
+
return LatchUnsignaledConfig::Disabled;
}
@@ -478,7 +478,8 @@
mBootFinished = false;
// Sever the link to inputflinger since it's gone as well.
- static_cast<void>(mScheduler->schedule([=] { mInputFlinger = nullptr; }));
+ static_cast<void>(mScheduler->schedule(
+ [this] { mInputFlinger.clear(); }));
// restore initial conditions (default device unblank, etc)
initializeDisplays();
@@ -506,7 +507,7 @@
virtual ~DisplayToken() {
// no more references, this display must be terminated
Mutex::Autolock _l(flinger->mStateLock);
- flinger->mCurrentState.displays.removeItem(this);
+ flinger->mCurrentState.displays.removeItem(wp<IBinder>::fromExisting(this));
flinger->setTransactionFlags(eDisplayTransactionNeeded);
}
public:
@@ -515,7 +516,7 @@
}
};
- sp<BBinder> token = new DisplayToken(this);
+ sp<BBinder> token = sp<DisplayToken>::make(sp<SurfaceFlinger>::fromExisting(this));
Mutex::Autolock _l(mStateLock);
// Display ID is assigned when virtual display is allocated by HWC.
@@ -607,12 +608,6 @@
return displayIds;
}
-status_t SurfaceFlinger::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) const {
- Mutex::Autolock lock(mStateLock);
- *id = getPrimaryDisplayIdLocked();
- return NO_ERROR;
-}
-
sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
Mutex::Autolock lock(mStateLock);
return getPhysicalDisplayTokenLocked(displayId);
@@ -663,7 +658,7 @@
const String16 name("window");
mWindowManager = defaultServiceManager()->getService(name);
if (mWindowManager != 0) {
- mWindowManager->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
+ mWindowManager->linkToDeath(sp<IBinder::DeathRecipient>::fromExisting(this));
}
// stop boot animation
@@ -1448,18 +1443,6 @@
}));
}
-status_t SurfaceFlinger::clearAnimationFrameStats() {
- Mutex::Autolock _l(mStateLock);
- mAnimFrameTracker.clearStats();
- return NO_ERROR;
-}
-
-status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const {
- Mutex::Autolock _l(mStateLock);
- mAnimFrameTracker.getStats(outStats);
- return NO_ERROR;
-}
-
status_t SurfaceFlinger::overrideHdrTypes(const sp<IBinder>& displayToken,
const std::vector<ui::Hdr>& hdrTypes) {
Mutex::Autolock lock(mStateLock);
@@ -1569,7 +1552,7 @@
status_t SurfaceFlinger::injectVSync(nsecs_t when) {
Mutex::Autolock lock(mStateLock);
- const nsecs_t expectedPresentTime = calculateExpectedPresentTime(when).ns();
+ const nsecs_t expectedPresentTime = calculateExpectedPresentTime(TimePoint::fromNs(when)).ns();
const nsecs_t deadlineTimestamp = expectedPresentTime;
return mScheduler->injectVSync(when, expectedPresentTime, deadlineTimestamp) ? NO_ERROR
: BAD_VALUE;
@@ -1944,9 +1927,9 @@
}));
}
-auto SurfaceFlinger::getPreviousPresentFence(nsecs_t frameTime, Period vsyncPeriod)
+auto SurfaceFlinger::getPreviousPresentFence(TimePoint frameTime, Period vsyncPeriod)
-> const FenceTimePtr& {
- const bool isTwoVsyncsAhead = mExpectedPresentTime - frameTime > vsyncPeriod.ns();
+ const bool isTwoVsyncsAhead = mExpectedPresentTime - frameTime > vsyncPeriod;
const size_t i = static_cast<size_t>(isTwoVsyncsAhead);
return mPreviousPresentFences[i].fenceTime;
}
@@ -1963,10 +1946,10 @@
return status == -ETIME;
}
-TimePoint SurfaceFlinger::calculateExpectedPresentTime(nsecs_t frameTime) const {
+TimePoint SurfaceFlinger::calculateExpectedPresentTime(TimePoint frameTime) const {
const auto& schedule = mScheduler->getVsyncSchedule();
- const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(TimePoint::fromNs(frameTime));
+ const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(frameTime);
if (mVsyncModulator->getVsyncConfig().sfOffset > 0) {
return vsyncDeadline;
}
@@ -1975,25 +1958,21 @@
return vsyncDeadline + schedule.period();
}
-bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime)
+bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime)
FTL_FAKE_GUARD(kMainThreadContext) {
// The expectedVsyncTime, which was predicted when this frame was scheduled, is normally in the
// future relative to frameTime, but may not be for delayed frames. Adjust mExpectedPresentTime
// accordingly, but not mScheduledPresentTime.
- const nsecs_t lastScheduledPresentTime = mScheduledPresentTime;
+ const TimePoint lastScheduledPresentTime = mScheduledPresentTime;
mScheduledPresentTime = expectedVsyncTime;
// Calculate the expected present time once and use the cached value throughout this frame to
// make sure all layers are seeing this same value.
- mExpectedPresentTime = expectedVsyncTime >= frameTime
- ? expectedVsyncTime
- : calculateExpectedPresentTime(frameTime).ns();
+ mExpectedPresentTime = expectedVsyncTime >= frameTime ? expectedVsyncTime
+ : calculateExpectedPresentTime(frameTime);
- const auto vsyncIn = [&] {
- if (!ATRACE_ENABLED()) return 0.f;
- return (mExpectedPresentTime - systemTime()) / 1e6f;
- }();
- ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId, vsyncIn,
+ ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId.value,
+ ticks<std::milli, float>(mExpectedPresentTime - scheduler::SchedulerClock::now()),
mExpectedPresentTime == expectedVsyncTime ? "" : " (adjusted)");
const Period vsyncPeriod = mScheduler->getVsyncSchedule().period();
@@ -2023,7 +2002,7 @@
const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed",
framePending ||
(previousPresentTime >= 0 &&
- (lastScheduledPresentTime <
+ (lastScheduledPresentTime.ns() <
previousPresentTime - frameMissedSlop))};
const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
mHadDeviceComposition && frameMissed};
@@ -2073,20 +2052,23 @@
}
// Save this once per commit + composite to ensure consistency
- mPowerHintSessionEnabled = mPowerAdvisor->usePowerHintSession();
+ // TODO (b/240619471): consider removing active display check once AOD is fixed
+ const auto activeDisplay =
+ FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(mActiveDisplayToken));
+ mPowerHintSessionEnabled = mPowerAdvisor->usePowerHintSession() && activeDisplay &&
+ activeDisplay->getPowerMode() == hal::PowerMode::ON;
if (mPowerHintSessionEnabled) {
- nsecs_t vsyncPeriod;
- {
- Mutex::Autolock lock(mStateLock);
- vsyncPeriod = getVsyncPeriodFromHWC();
- }
- mPowerAdvisor->setCommitStart(frameTime);
- mPowerAdvisor->setExpectedPresentTime(mExpectedPresentTime);
- const nsecs_t idealSfWorkDuration =
- mVsyncModulator->getVsyncConfig().sfWorkDuration.count();
- // Frame delay is how long we should have minus how long we actually have
- mPowerAdvisor->setFrameDelay(idealSfWorkDuration - (mExpectedPresentTime - frameTime));
- mPowerAdvisor->setTotalFrameTargetWorkDuration(idealSfWorkDuration);
+ const auto& display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
+ const nsecs_t vsyncPeriod = display->getActiveMode()->getVsyncPeriod();
+ mPowerAdvisor->setCommitStart(frameTime.ns());
+ mPowerAdvisor->setExpectedPresentTime(mExpectedPresentTime.ns());
+
+ // Frame delay is how long we should have minus how long we actually have.
+ const Duration idealSfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration;
+ const Duration frameDelay = idealSfWorkDuration - (mExpectedPresentTime - frameTime);
+
+ mPowerAdvisor->setFrameDelay(frameDelay.ns());
+ mPowerAdvisor->setTotalFrameTargetWorkDuration(idealSfWorkDuration.ns());
mPowerAdvisor->setTargetWorkDuration(vsyncPeriod);
// Send early hint here to make sure there's not another frame pending
@@ -2106,10 +2088,12 @@
// Composite if transactions were committed, or if requested by HWC.
bool mustComposite = mMustComposite.exchange(false);
{
- mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(vsyncPeriod.ns()));
+ mFrameTimeline->setSfWakeUp(vsyncId.value, frameTime.ns(),
+ Fps::fromPeriodNsecs(vsyncPeriod.ns()));
bool needsTraversal = false;
if (clearTransactionFlags(eTransactionFlushNeeded)) {
+ needsTraversal |= commitMirrorDisplays(vsyncId);
needsTraversal |= commitCreatedLayers(vsyncId);
needsTraversal |= flushTransactionQueues(vsyncId);
}
@@ -2155,7 +2139,7 @@
if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
// This will block and tracing should only be enabled for debugging.
- mLayerTracing.notify(mVisibleRegionsDirty, frameTime, vsyncId);
+ mLayerTracing.notify(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value);
}
mLastCommittedVsyncId = vsyncId;
@@ -2164,9 +2148,9 @@
return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}
-void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId)
+void SurfaceFlinger::composite(TimePoint frameTime, VsyncId vsyncId)
FTL_FAKE_GUARD(kMainThreadContext) {
- ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId);
+ ATRACE_FORMAT("%s %" PRId64, __func__, vsyncId.value);
compositionengine::CompositionRefreshArgs refreshArgs;
const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays);
@@ -2226,15 +2210,13 @@
refreshArgs.devOptFlashDirtyRegionsDelay = std::chrono::milliseconds(mDebugFlashDelay);
}
- const auto expectedPresentTime = mExpectedPresentTime.load();
- const auto prevVsyncTime =
- TimePoint::fromNs(expectedPresentTime) - mScheduler->getVsyncSchedule().period();
-
+ const auto prevVsyncTime = mExpectedPresentTime - mScheduler->getVsyncSchedule().period();
const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
+
refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime;
refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
- refreshArgs.expectedPresentTime = expectedPresentTime;
+ refreshArgs.expectedPresentTime = mExpectedPresentTime.ns();
// Store the present time just before calling to the composition engine so we could notify
// the scheduler.
@@ -2242,11 +2224,12 @@
mCompositionEngine->present(refreshArgs);
- mTimeStats->recordFrameDuration(frameTime, systemTime());
+ mTimeStats->recordFrameDuration(frameTime.ns(), systemTime());
// Send a power hint hint after presentation is finished
if (mPowerHintSessionEnabled) {
- mPowerAdvisor->setPresentFenceTime(mPreviousPresentFences[0].fenceTime->getSignalTime());
+ mPowerAdvisor->setSfPresentTiming(mPreviousPresentFences[0].fenceTime->getSignalTime(),
+ systemTime());
if (mPowerHintSessionMode.late) {
mPowerAdvisor->sendActualWorkDuration();
}
@@ -2256,7 +2239,6 @@
scheduleComposite(FrameHint::kNone);
}
- postFrame();
postComposition();
const bool prevFrameHadClientComposition = mHadClientComposition;
@@ -2286,7 +2268,7 @@
mLayersWithQueuedFrames.clear();
if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
// This will block and should only be used for debugging.
- mLayerTracing.notify(mVisibleRegionsDirty, frameTime, vsyncId);
+ mLayerTracing.notify(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value);
}
mVisibleRegionsWereDirtyThisFrame = mVisibleRegionsDirty; // Cache value for use in post-comp
@@ -2316,32 +2298,6 @@
mLayersPendingRefresh.clear();
}
-nsecs_t SurfaceFlinger::trackPresentLatency(nsecs_t compositeTime,
- std::shared_ptr<FenceTime> presentFenceTime) {
- // Update queue of past composite+present times and determine the
- // most recently known composite to present latency.
- getBE().mCompositePresentTimes.push({compositeTime, std::move(presentFenceTime)});
- nsecs_t compositeToPresentLatency = -1;
- while (!getBE().mCompositePresentTimes.empty()) {
- SurfaceFlingerBE::CompositePresentTime& cpt = getBE().mCompositePresentTimes.front();
- // Cached values should have been updated before calling this method,
- // which helps avoid duplicate syscalls.
- nsecs_t displayTime = cpt.display->getCachedSignalTime();
- if (displayTime == Fence::SIGNAL_TIME_PENDING) {
- break;
- }
- compositeToPresentLatency = displayTime - cpt.composite;
- getBE().mCompositePresentTimes.pop();
- }
-
- // Don't let mCompositePresentTimes grow unbounded, just in case.
- while (getBE().mCompositePresentTimes.size() > 16) {
- getBE().mCompositePresentTimes.pop();
- }
-
- return compositeToPresentLatency;
-}
-
bool SurfaceFlinger::isHdrLayer(Layer* layer) const {
// Treat all layers as non-HDR if:
// 1. They do not have a valid HDR dataspace. Currently we treat those as PQ or HLG. and
@@ -2398,7 +2354,7 @@
void SurfaceFlinger::postComposition() {
ATRACE_CALL();
- ALOGV("postComposition");
+ ALOGV(__func__);
const auto* display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
@@ -2413,38 +2369,40 @@
}
mPreviousPresentFences[1] = mPreviousPresentFences[0];
- mPreviousPresentFences[0].fence =
- display ? getHwComposer().getPresentFence(display->getPhysicalId()) : Fence::NO_FENCE;
- mPreviousPresentFences[0].fenceTime =
- std::make_shared<FenceTime>(mPreviousPresentFences[0].fence);
- nsecs_t now = systemTime();
+ auto presentFence =
+ display ? getHwComposer().getPresentFence(display->getPhysicalId()) : Fence::NO_FENCE;
+
+ auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
+ mPreviousPresentFences[0] = {presentFence, presentFenceTime};
+
+ const TimePoint presentTime = scheduler::SchedulerClock::now();
// Set presentation information before calling Layer::releasePendingBuffer, such that jank
// information from previous' frame classification is already available when sending jank info
// to clients, so they get jank classification as early as possible.
- mFrameTimeline->setSfPresent(/* sfPresentTime */ now, mPreviousPresentFences[0].fenceTime,
- glCompositionDoneFenceTime);
+ mFrameTimeline->setSfPresent(presentTime.ns(), presentFenceTime, glCompositionDoneFenceTime);
// We use the CompositionEngine::getLastFrameRefreshTimestamp() which might
// be sampled a little later than when we started doing work for this frame,
// but that should be okay since CompositorTiming has snapping logic.
- const nsecs_t compositeTime = mCompositionEngine->getLastFrameRefreshTimestamp();
- const nsecs_t presentLatency =
- trackPresentLatency(compositeTime, mPreviousPresentFences[0].fenceTime);
+ const TimePoint compositeTime =
+ TimePoint::fromNs(mCompositionEngine->getLastFrameRefreshTimestamp());
+ const Duration presentLatency =
+ mPresentLatencyTracker.trackPendingFrame(compositeTime, presentFenceTime);
const auto& schedule = mScheduler->getVsyncSchedule();
- const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(TimePoint::fromNs(now));
+ const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(presentTime);
const Period vsyncPeriod = schedule.period();
const nsecs_t vsyncPhase = mVsyncConfiguration->getCurrentConfigs().late.sfOffset;
const CompositorTiming compositorTiming(vsyncDeadline.ns(), vsyncPeriod.ns(), vsyncPhase,
- presentLatency);
+ presentLatency.ns());
for (const auto& layer: mLayersWithQueuedFrames) {
- layer->onPostComposition(display, glCompositionDoneFenceTime,
- mPreviousPresentFences[0].fenceTime, compositorTiming);
- layer->releasePendingBuffer(/*dequeueReadyTime*/ now);
+ layer->onPostComposition(display, glCompositionDoneFenceTime, presentFenceTime,
+ compositorTiming);
+ layer->releasePendingBuffer(presentTime.ns());
}
std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>>
@@ -2501,13 +2459,16 @@
mSomeDataspaceChanged = false;
mVisibleRegionsWereDirtyThisFrame = false;
- mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence);
+ mTransactionCallbackInvoker.addPresentFence(std::move(presentFence));
mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */);
mTransactionCallbackInvoker.clearCompletedTransactions();
+ mTimeStats->incrementTotalFrames();
+ mTimeStats->setPresentFenceGlobal(presentFenceTime);
+
if (display && display->isInternal() && display->getPowerMode() == hal::PowerMode::ON &&
- mPreviousPresentFences[0].fenceTime->isValid()) {
- mScheduler->addPresentFence(mPreviousPresentFences[0].fenceTime);
+ presentFenceTime->isValid()) {
+ mScheduler->addPresentFence(std::move(presentFenceTime));
}
const bool isDisplayConnected =
@@ -2519,24 +2480,6 @@
}
}
- if (mAnimCompositionPending) {
- mAnimCompositionPending = false;
-
- if (mPreviousPresentFences[0].fenceTime->isValid()) {
- mAnimFrameTracker.setActualPresentFence(mPreviousPresentFences[0].fenceTime);
- } else if (isDisplayConnected) {
- // The HWC doesn't support present fences, so use the refresh
- // timestamp instead.
- const nsecs_t presentTime = display->getRefreshTimestamp();
- mAnimFrameTracker.setActualPresentTime(presentTime);
- }
- mAnimFrameTracker.advanceFrame();
- }
-
- mTimeStats->incrementTotalFrames();
-
- mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime);
-
const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle);
const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle);
mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections);
@@ -2546,21 +2489,6 @@
return;
}
- nsecs_t currentTime = systemTime();
- if (mHasPoweredOff) {
- mHasPoweredOff = false;
- } else {
- nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
- const size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncPeriod.ns());
- if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
- getBE().mFrameBuckets[numPeriods] += elapsedTime;
- } else {
- getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] += elapsedTime;
- }
- getBE().mTotalTime += elapsedTime;
- }
- getBE().mLastSwapTime = currentTime;
-
// Cleanup any outstanding resources due to rendering a prior frame.
getRenderEngine().cleanupPostRender();
@@ -2587,6 +2515,8 @@
// getTotalSize returns the total number of buffers that were allocated by SurfaceFlinger
ATRACE_INT64("Total Buffer Size", GraphicBufferAllocator::get().getTotalSize());
}
+
+ logFrameStats(presentTime);
}
FloatRect SurfaceFlinger::getMaxDisplayBounds() {
@@ -2619,16 +2549,6 @@
}
}
-void SurfaceFlinger::postFrame() {
- const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
- if (display && getHwComposer().isConnected(display->getPhysicalId())) {
- uint32_t flipCount = display->getPageFlipCount();
- if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
- logFrameStats();
- }
- }
-}
-
void SurfaceFlinger::commitTransactions() {
ATRACE_CALL();
@@ -2747,7 +2667,7 @@
state.isSecure = true; // All physical displays are currently considered secure.
state.displayName = std::move(info->name);
- sp<IBinder> token = new BBinder();
+ sp<IBinder> token = sp<BBinder>::make();
mCurrentState.displays.add(token, state);
mPhysicalDisplayTokens.try_emplace(displayId, std::move(token));
mInterceptor->saveDisplayCreation(state);
@@ -2793,7 +2713,8 @@
const DisplayDeviceState& state,
const sp<compositionengine::DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer) {
- DisplayDeviceCreationArgs creationArgs(this, getHwComposer(), displayToken, compositionDisplay);
+ DisplayDeviceCreationArgs creationArgs(sp<SurfaceFlinger>::fromExisting(this), getHwComposer(),
+ displayToken, compositionDisplay);
creationArgs.sequenceId = state.sequenceId;
creationArgs.isSecure = state.isSecure;
creationArgs.displaySurface = displaySurface;
@@ -3192,18 +3113,17 @@
mVisibleRegionsDirty = true;
mUpdateInputInfo = true;
mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (mLayersPendingRemoval.indexOf(layer) >= 0) {
+ if (mLayersPendingRemoval.indexOf(sp<Layer>::fromExisting(layer)) >= 0) {
// this layer is not visible anymore
Region visibleReg;
visibleReg.set(layer->getScreenBounds());
- invalidateLayerStack(layer, visibleReg);
+ invalidateLayerStack(sp<Layer>::fromExisting(layer), visibleReg);
}
});
}
doCommitTransactions();
signalSynchronousTransactions(CountDownLatch::eSyncTransaction);
- mAnimTransactionPending = false;
}
void SurfaceFlinger::updateInputFlinger() {
@@ -3312,11 +3232,11 @@
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (!layer->needsInputInfo()) return;
- // Do not create WindowInfos for windows on displays that cannot receive input.
- if (const auto opt = displayInputInfos.get(layer->getLayerStack())) {
- const auto& info = opt->get();
- outWindowInfos.push_back(layer->fillInputInfo(info.transform, info.isSecure));
- }
+ const auto opt = displayInputInfos.get(layer->getLayerStack(),
+ [](const auto& info) -> Layer::InputDisplayArgs {
+ return {&info.transform, info.isSecure};
+ });
+ outWindowInfos.push_back(layer->fillInputInfo(opt.value_or(Layer::InputDisplayArgs{})));
});
sNumWindowInfos = outWindowInfos.size();
@@ -3432,8 +3352,9 @@
*mFrameTimeline->getTokenManager(), configs.late.sfWorkDuration);
mRegionSamplingThread =
- new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables());
- mFpsReporter = new FpsReporter(*mFrameTimeline, *this);
+ sp<RegionSamplingThread>::make(*this,
+ RegionSamplingThread::EnvironmentTimingTunables());
+ mFpsReporter = sp<FpsReporter>::make(*mFrameTimeline, *this);
// Dispatch a mode change request for the primary display on scheduler
// initialization, so that the EventThreads always contain a reference to a
// prior configuration.
@@ -3491,10 +3412,6 @@
mLayersPendingRemoval.clear();
}
- // If this transaction is part of a window animation then the next frame
- // we composite should be considered an animation as well.
- mAnimCompositionPending = mAnimTransactionPending;
-
mDrawingState = mCurrentState;
// clear the "changed" flags in current state
mCurrentState.colorMatrixChanged = false;
@@ -3540,8 +3457,6 @@
bool frameQueued = false;
bool newDataLatched = false;
- const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
-
// Store the set of layers that need updates. This set must not change as
// buffers are being latched, as this could result in a deadlock.
// Example: Two producers share the same command stream and:
@@ -3561,12 +3476,7 @@
if (layer->hasReadyFrame()) {
frameQueued = true;
- if (layer->shouldPresentNow(expectedPresentTime)) {
- mLayersWithQueuedFrames.emplace(layer);
- } else {
- ATRACE_NAME("!layer->shouldPresentNow()");
- layer->useEmptyDamage();
- }
+ mLayersWithQueuedFrames.emplace(sp<Layer>::fromExisting(layer));
} else {
layer->useEmptyDamage();
}
@@ -3587,7 +3497,7 @@
Mutex::Autolock lock(mStateLock);
for (const auto& layer : mLayersWithQueuedFrames) {
- if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) {
+ if (layer->latchBuffer(visibleRegions, latchTime)) {
mLayersPendingRefresh.push_back(layer);
newDataLatched = true;
}
@@ -3679,52 +3589,33 @@
}
}
-bool SurfaceFlinger::stopTransactionProcessing(
- const std::unordered_set<sp<IBinder>, SpHash<IBinder>>&
- applyTokensWithUnsignaledTransactions) const {
- if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) {
- // if we are in LatchUnsignaledConfig::AutoSingleLayer
- // then we should have only one applyToken for processing.
- // so we can stop further transactions on this applyToken.
- return !applyTokensWithUnsignaledTransactions.empty();
- }
-
- return false;
-}
-
-int SurfaceFlinger::flushUnsignaledPendingTransactionQueues(
- std::vector<TransactionState>& transactions,
- std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
- std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions) {
- return flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
- applyTokensWithUnsignaledTransactions,
- /*tryApplyUnsignaled*/ true);
-}
-
int SurfaceFlinger::flushPendingTransactionQueues(
std::vector<TransactionState>& transactions,
std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
- std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions,
bool tryApplyUnsignaled) {
+ std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions;
int transactionsPendingBarrier = 0;
auto it = mPendingTransactionQueues.begin();
while (it != mPendingTransactionQueues.end()) {
auto& [applyToken, transactionQueue] = *it;
while (!transactionQueue.empty()) {
- if (stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) {
+ // if we are in LatchUnsignaledConfig::AutoSingleLayer
+ // then we should have only one applyToken for processing.
+ // so we can stop further transactions on this applyToken.
+ if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer &&
+ !applyTokensWithUnsignaledTransactions.empty()) {
ATRACE_NAME("stopTransactionProcessing");
break;
}
auto& transaction = transactionQueue.front();
const auto ready =
- transactionIsReadyToBeApplied(transaction,
- transaction.frameTimelineInfo,
- transaction.isAutoTimestamp,
- transaction.desiredPresentTime,
- transaction.originUid, transaction.states,
- bufferLayersReadyToPresent, transactions.size(),
- tryApplyUnsignaled);
+ transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo,
+ transaction.isAutoTimestamp,
+ TimePoint::fromNs(transaction.desiredPresentTime),
+ transaction.originUid, transaction.states,
+ bufferLayersReadyToPresent, transactions.size(),
+ tryApplyUnsignaled);
ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
if (ready == TransactionReadiness::NotReady) {
setTransactionFlags(eTransactionFlushNeeded);
@@ -3753,11 +3644,12 @@
transactions.emplace_back(std::move(transaction));
transactionQueue.pop();
+ mPendingTransactionCount--;
+ ATRACE_INT("TransactionQueue", mPendingTransactionCount.load());
}
if (transactionQueue.empty()) {
it = mPendingTransactionQueues.erase(it);
- mTransactionQueueCV.broadcast();
} else {
it = std::next(it, 1);
}
@@ -3765,73 +3657,23 @@
return transactionsPendingBarrier;
}
-bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) {
+bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) {
// to prevent onHandleDestroyed from being called while the lock is held,
// we must keep a copy of the transactions (specifically the composer
// states) around outside the scope of the lock
std::vector<TransactionState> transactions;
// Layer handles that have transactions with buffers that are ready to be applied.
std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>> bufferLayersReadyToPresent;
- std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions;
{
Mutex::Autolock _l(mStateLock);
{
- Mutex::Autolock _l(mQueueLock);
-
- int lastTransactionsPendingBarrier = 0;
- int transactionsPendingBarrier = 0;
- // First collect transactions from the pending transaction queues.
- // We are not allowing unsignaled buffers here as we want to
- // collect all the transactions from applyTokens that are ready first.
- transactionsPendingBarrier =
- flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
- applyTokensWithUnsignaledTransactions, /*tryApplyUnsignaled*/ false);
-
- // Second, collect transactions from the transaction queue.
- // Here as well we are not allowing unsignaled buffers for the same
- // reason as above.
- while (!mTransactionQueue.empty()) {
- auto& transaction = mTransactionQueue.front();
- const bool pendingTransactions =
- mPendingTransactionQueues.find(transaction.applyToken) !=
- mPendingTransactionQueues.end();
- const auto ready = [&]() REQUIRES(mStateLock) {
- if (pendingTransactions) {
- ATRACE_NAME("pendingTransactions");
- return TransactionReadiness::NotReady;
- }
-
- return transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo,
- transaction.isAutoTimestamp,
- transaction.desiredPresentTime,
- transaction.originUid, transaction.states,
- bufferLayersReadyToPresent,
- transactions.size(),
- /*tryApplyUnsignaled*/ false);
- }();
- ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
- if (ready != TransactionReadiness::Ready) {
- if (ready == TransactionReadiness::NotReadyBarrier) {
- transactionsPendingBarrier++;
- }
- mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction));
- } else {
- transaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
- const bool frameNumberChanged = state.bufferData->flags.test(
- BufferData::BufferDataChange::frameNumberChanged);
- if (frameNumberChanged) {
- bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber;
- } else {
- // Barrier function only used for BBQ which always includes a frame number.
- // This value only used for barrier logic.
- bufferLayersReadyToPresent[state.surface] =
- std::numeric_limits<uint64_t>::max();
- }
- });
- transactions.emplace_back(std::move(transaction));
+ while (!mLocklessTransactionQueue.isEmpty()) {
+ auto maybeTransaction = mLocklessTransactionQueue.pop();
+ if (!maybeTransaction.has_value()) {
+ break;
}
- mTransactionQueue.pop_front();
- ATRACE_INT("TransactionQueue", mTransactionQueue.size());
+ auto transaction = maybeTransaction.value();
+ mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction));
}
// Transactions with a buffer pending on a barrier may be on a different applyToken
@@ -3844,20 +3686,21 @@
// loop through flushPendingTransactionQueues until we perform an iteration
// where the number of transactionsPendingBarrier doesn't change. This way
// we can continue to resolve dependency chains of barriers as far as possible.
- while (lastTransactionsPendingBarrier != transactionsPendingBarrier) {
+ int lastTransactionsPendingBarrier = 0;
+ int transactionsPendingBarrier = 0;
+ do {
lastTransactionsPendingBarrier = transactionsPendingBarrier;
transactionsPendingBarrier =
- flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
- applyTokensWithUnsignaledTransactions,
- /*tryApplyUnsignaled*/ false);
- }
+ flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
+ /*tryApplyUnsignaled*/ false);
+ } while (lastTransactionsPendingBarrier != transactionsPendingBarrier);
// We collected all transactions that could apply without latching unsignaled buffers.
// If we are allowing latch unsignaled of some form, now it's the time to go over the
// transactions that were not applied and try to apply them unsignaled.
if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) {
- flushUnsignaledPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
- applyTokensWithUnsignaledTransactions);
+ flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent,
+ /*tryApplyUnsignaled*/ true);
}
return applyTransactions(transactions, vsyncId);
@@ -3866,7 +3709,7 @@
}
bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions,
- int64_t vsyncId) {
+ VsyncId vsyncId) {
bool needsTraversal = false;
// Now apply all transactions.
for (auto& transaction : transactions) {
@@ -3886,37 +3729,37 @@
}
if (mTransactionTracing) {
- mTransactionTracing->addCommittedTransactions(transactions, vsyncId);
+ mTransactionTracing->addCommittedTransactions(transactions, vsyncId.value);
}
return needsTraversal;
}
bool SurfaceFlinger::transactionFlushNeeded() {
- Mutex::Autolock _l(mQueueLock);
- return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty();
+ return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty();
}
-bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const {
- // The amount of time SF can delay a frame if it is considered early based
- // on the VsyncModulator::VsyncConfig::appWorkDuration
- constexpr std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms;
-
- const nsecs_t currentVsyncPeriod = mScheduler->getVsyncSchedule().period().ns();
- const nsecs_t earlyLatchVsyncThreshold = currentVsyncPeriod / 2;
-
- const auto prediction = mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId);
- if (!prediction.has_value()) {
+bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId) const {
+ const auto prediction =
+ mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId.value);
+ if (!prediction) {
return false;
}
- if (std::abs(prediction->presentTime - expectedPresentTime) >=
- kEarlyLatchMaxThreshold.count()) {
+ const auto predictedPresentTime = TimePoint::fromNs(prediction->presentTime);
+
+ // The duration for which SF can delay a frame if it is considered early based on the
+ // VsyncModulator::VsyncConfig::appWorkDuration.
+ if (constexpr std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms;
+ std::chrono::abs(predictedPresentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold) {
return false;
}
- return prediction->presentTime >= expectedPresentTime &&
- prediction->presentTime - expectedPresentTime >= earlyLatchVsyncThreshold;
+ const Duration earlyLatchVsyncThreshold = mScheduler->getVsyncSchedule().period() / 2;
+
+ return predictedPresentTime >= expectedPresentTime &&
+ predictedPresentTime - expectedPresentTime >= earlyLatchVsyncThreshold;
}
+
bool SurfaceFlinger::shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t& state,
size_t numStates, size_t totalTXapplied) const {
if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) {
@@ -3963,30 +3806,29 @@
return true;
}
-auto SurfaceFlinger::transactionIsReadyToBeApplied(TransactionState& transaction,
- const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
- uid_t originUid, const Vector<ComposerState>& states,
- const std::unordered_map<
- sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
+auto SurfaceFlinger::transactionIsReadyToBeApplied(
+ TransactionState& transaction, const FrameTimelineInfo& info, bool isAutoTimestamp,
+ TimePoint desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states,
+ const std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>&
+ bufferLayersReadyToPresent,
size_t totalTXapplied, bool tryApplyUnsignaled) const -> TransactionReadiness {
ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId);
- const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
// Do not present if the desiredPresentTime has not passed unless it is more than one second
// in the future. We ignore timestamps more than 1 second in the future for stability reasons.
- if (!isAutoTimestamp && desiredPresentTime >= expectedPresentTime &&
- desiredPresentTime < expectedPresentTime + s2ns(1)) {
+ if (!isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime &&
+ desiredPresentTime < mExpectedPresentTime + 1s) {
ATRACE_NAME("not current");
return TransactionReadiness::NotReady;
}
- if (!mScheduler->isVsyncValid(expectedPresentTime, originUid)) {
+ if (!mScheduler->isVsyncValid(mExpectedPresentTime, originUid)) {
ATRACE_NAME("!isVsyncValid");
return TransactionReadiness::NotReady;
}
// If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected
// present time of this transaction.
- if (isAutoTimestamp && frameIsEarly(expectedPresentTime, info.vsyncId)) {
+ if (isAutoTimestamp && frameIsEarly(mExpectedPresentTime, VsyncId{info.vsyncId})) {
ATRACE_NAME("frameIsEarly");
return TransactionReadiness::NotReady;
}
@@ -4032,7 +3874,7 @@
if (fenceUnsignaled && !allowLatchUnsignaled) {
if (!transaction.sentFenceTimeoutWarning &&
- queueProcessTime - transaction.queueTime > std::chrono::nanoseconds(4s).count()) {
+ queueProcessTime - transaction.postTime > std::chrono::nanoseconds(4s).count()) {
transaction.sentFenceTimeoutWarning = true;
auto listener = s.bufferData->releaseBufferListener;
if (listener) {
@@ -4059,18 +3901,15 @@
}
void SurfaceFlinger::queueTransaction(TransactionState& state) {
- state.queueTime = systemTime();
-
- Mutex::Autolock lock(mQueueLock);
-
// Generate a CountDownLatch pending state if this is a synchronous transaction.
if (state.flags & eSynchronous) {
state.transactionCommittedSignal =
std::make_shared<CountDownLatch>(CountDownLatch::eSyncTransaction);
}
- mTransactionQueue.emplace_back(state);
- ATRACE_INT("TransactionQueue", mTransactionQueue.size());
+ mLocklessTransactionQueue.push(state);
+ mPendingTransactionCount++;
+ ATRACE_INT("TransactionQueue", mPendingTransactionCount.load());
const auto schedule = [](uint32_t flags) {
if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
@@ -4239,10 +4078,6 @@
if (transactionFlags) {
setTransactionFlags(transactionFlags);
}
-
- if (flags & eAnimation) {
- mAnimTransactionPending = true;
- }
}
return needsTraversal;
@@ -4351,7 +4186,7 @@
if (layer == nullptr) {
for (auto& [listener, callbackIds] : s.listeners) {
mTransactionCallbackInvoker.registerUnpresentedCallbackHandle(
- new CallbackHandle(listener, callbackIds, s.surface));
+ sp<CallbackHandle>::make(listener, callbackIds, s.surface));
}
return 0;
}
@@ -4605,7 +4440,8 @@
std::vector<sp<CallbackHandle>> callbackHandles;
if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!filteredListeners.empty())) {
for (auto& [listener, callbackIds] : filteredListeners) {
- callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
+ callbackHandles.emplace_back(
+ sp<CallbackHandle>::make(listener, callbackIds, s.surface));
}
}
@@ -4646,7 +4482,9 @@
if (!mirrorFrom) {
return NAME_NOT_FOUND;
}
- status_t result = createContainerLayer(args, outHandle, &mirrorLayer);
+ LayerCreationArgs mirrorArgs = args;
+ mirrorArgs.flags |= ISurfaceComposerClient::eNoColorFill;
+ status_t result = createEffectLayer(mirrorArgs, outHandle, &mirrorLayer);
if (result != NO_ERROR) {
return result;
}
@@ -4663,6 +4501,55 @@
false /* addToRoot */, nullptr /* outTransformHint */);
}
+status_t SurfaceFlinger::mirrorDisplay(DisplayId displayId, const LayerCreationArgs& args,
+ sp<IBinder>* outHandle, int32_t* outLayerId) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int uid = ipc->getCallingUid();
+ if (uid != AID_ROOT && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != AID_SHELL) {
+ ALOGE("Permission denied when trying to mirror display");
+ return PERMISSION_DENIED;
+ }
+
+ ui::LayerStack layerStack;
+ sp<Layer> rootMirrorLayer;
+ status_t result = 0;
+
+ {
+ Mutex::Autolock lock(mStateLock);
+
+ const auto display = getDisplayDeviceLocked(displayId);
+ if (!display) {
+ return NAME_NOT_FOUND;
+ }
+
+ layerStack = display->getLayerStack();
+ LayerCreationArgs mirrorArgs = args;
+ mirrorArgs.flags |= ISurfaceComposerClient::eNoColorFill;
+ result = createEffectLayer(mirrorArgs, outHandle, &rootMirrorLayer);
+ *outLayerId = rootMirrorLayer->sequence;
+ result |= addClientLayer(args.client, *outHandle, rootMirrorLayer /* layer */,
+ nullptr /* parent */, true /* addToRoot */,
+ nullptr /* outTransformHint */);
+ }
+
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ if (mTransactionTracing) {
+ mTransactionTracing->onLayerAdded((*outHandle)->localBinder(), *outLayerId, args.name,
+ args.flags, -1 /* parentId */);
+ }
+
+ {
+ std::scoped_lock<std::mutex> lock(mMirrorDisplayLock);
+ mMirrorDisplays.emplace_back(layerStack, *outHandle, args.client);
+ }
+
+ setTransactionFlags(eTransactionFlushNeeded);
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
const sp<IBinder>& parentHandle, int32_t* outLayerId,
const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
@@ -4685,12 +4572,12 @@
pendingBufferCounter);
}
} break;
+ case ISurfaceComposerClient::eFXSurfaceContainer:
+ args.flags |= ISurfaceComposerClient::eNoColorFill;
+ FMT_FALLTHROUGH;
case ISurfaceComposerClient::eFXSurfaceEffect:
result = createEffectLayer(args, outHandle, &layer);
break;
- case ISurfaceComposerClient::eFXSurfaceContainer:
- result = createContainerLayer(args, outHandle, &layer);
- break;
default:
result = BAD_VALUE;
break;
@@ -4746,13 +4633,6 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::createContainerLayer(const LayerCreationArgs& args, sp<IBinder>* handle,
- sp<Layer>* outLayer) {
- *outLayer = getFactory().createContainerLayer(args);
- *handle = (*outLayer)->getHandle();
- return NO_ERROR;
-}
-
void SurfaceFlinger::markLayerPendingRemovalLocked(const sp<Layer>& layer) {
mLayersPendingRemoval.add(layer);
mLayersRemoved = true;
@@ -4802,8 +4682,7 @@
{}, mPid, getuid(), transactionId);
setPowerModeInternal(display, hal::PowerMode::ON);
- const nsecs_t vsyncPeriod = display->refreshRateConfigs().getActiveMode()->getVsyncPeriod();
- mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
+
mActiveDisplayTransformHint = display->getTransformHint();
}
@@ -4860,7 +4739,6 @@
}
mVisibleRegionsDirty = true;
- mHasPoweredOff = true;
scheduleComposite(FrameHint::kActive);
} else if (mode == hal::PowerMode::OFF) {
// Turn off the display
@@ -4950,11 +4828,11 @@
{"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
{"--list"s, dumper(&SurfaceFlinger::listLayersLocked)},
{"--planner"s, argsDumper(&SurfaceFlinger::dumpPlannerInfo)},
- {"--static-screen"s, dumper(&SurfaceFlinger::dumpStaticScreenStats)},
{"--timestats"s, protoDumper(&SurfaceFlinger::dumpTimeStats)},
{"--vsync"s, dumper(&SurfaceFlinger::dumpVSync)},
{"--wide-color"s, dumper(&SurfaceFlinger::dumpWideColorInfo)},
{"--frametimeline"s, argsDumper(&SurfaceFlinger::dumpFrameTimeline)},
+ {"--hwclayers"s, dumper(&SurfaceFlinger::dumpHwcLayersMinidumpLocked)},
};
const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
@@ -5015,17 +4893,14 @@
void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result) const {
StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriodFromHWC());
+ if (args.size() < 2) return;
- if (args.size() > 1) {
- const auto name = String8(args[1]);
- mCurrentState.traverseInZOrder([&](Layer* layer) {
- if (layer->getName() == name.string()) {
- layer->dumpFrameStats(result);
- }
- });
- } else {
- mAnimFrameTracker.dumpStats(result);
- }
+ const auto name = String8(args[1]);
+ mCurrentState.traverseInZOrder([&](Layer* layer) {
+ if (layer->getName() == name.string()) {
+ layer->dumpFrameStats(result);
+ }
+ });
}
void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) {
@@ -5037,8 +4912,6 @@
layer->clearFrameStats();
}
});
-
- mAnimFrameTracker.clearStats();
}
void SurfaceFlinger::dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const {
@@ -5049,12 +4922,13 @@
mFrameTimeline->parseArgs(args, result);
}
-void SurfaceFlinger::logFrameStats() {
- mDrawingState.traverse([&](Layer* layer) {
- layer->logFrameStats();
- });
+void SurfaceFlinger::logFrameStats(TimePoint now) {
+ static TimePoint sTimestamp = now;
+ if (now - sTimestamp < 30min) return;
+ sTimestamp = now;
- mAnimFrameTracker.logAndResetStats("<win-anim>");
+ ATRACE_CALL();
+ mDrawingState.traverse([&](Layer* layer) { layer->logFrameStats(); });
}
void SurfaceFlinger::appendSfConfigString(std::string& result) const {
@@ -5097,21 +4971,6 @@
}
}
-void SurfaceFlinger::dumpStaticScreenStats(std::string& result) const {
- result.append("Static screen stats:\n");
- for (size_t b = 0; b < SurfaceFlingerBE::NUM_BUCKETS - 1; ++b) {
- float bucketTimeSec = getBE().mFrameBuckets[b] / 1e9;
- float percent = 100.0f *
- static_cast<float>(getBE().mFrameBuckets[b]) / getBE().mTotalTime;
- StringAppendF(&result, " < %zd frames: %.3f s (%.1f%%)\n", b + 1, bucketTimeSec, percent);
- }
- float bucketTimeSec = getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] / 1e9;
- float percent = 100.0f *
- static_cast<float>(getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1]) / getBE().mTotalTime;
- StringAppendF(&result, " %zd+ frames: %.3f s (%.1f%%)\n", SurfaceFlingerBE::NUM_BUCKETS - 1,
- bucketTimeSec, percent);
-}
-
void SurfaceFlinger::dumpCompositionDisplays(std::string& result) const {
for (const auto& [token, display] : mDisplays) {
display->getCompositionDisplay()->dump(result);
@@ -5270,6 +5129,23 @@
result.append(future.get());
}
+void SurfaceFlinger::dumpHwcLayersMinidumpLocked(std::string& result) const {
+ for (const auto& [token, display] : mDisplays) {
+ const auto displayId = HalDisplayId::tryCast(display->getId());
+ if (!displayId) {
+ continue;
+ }
+
+ StringAppendF(&result, "Display %s (%s) HWC layers:\n", to_string(*displayId).c_str(),
+ (isDisplayActiveLocked(display) ? "active" : "inactive"));
+ Layer::miniDumpHeader(result);
+
+ const DisplayDevice& ref = *display;
+ mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, ref); });
+ result.append("\n");
+ }
+}
+
void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
const bool colorize = !args.empty() && args[0] == String16("--color");
Colorizer colorizer(colorize);
@@ -5307,9 +5183,6 @@
dumpVSync(result);
result.append("\n");
- dumpStaticScreenStats(result);
- result.append("\n");
-
StringAppendF(&result, "Total missed frame count: %u\n", mFrameMissedCount.load());
StringAppendF(&result, "HWC missed frame count: %u\n", mHwcFrameMissedCount.load());
StringAppendF(&result, "GPU missed frame count: %u\n\n", mGpuFrameMissedCount.load());
@@ -5404,23 +5277,7 @@
}
result.push_back('\n');
- /*
- * HWC layer minidump
- */
- for (const auto& [token, display] : mDisplays) {
- const auto displayId = HalDisplayId::tryCast(display->getId());
- if (!displayId) {
- continue;
- }
-
- StringAppendF(&result, "Display %s (%s) HWC layers:\n", to_string(*displayId).c_str(),
- (isDisplayActiveLocked(display) ? "active" : "inactive"));
- Layer::miniDumpHeader(result);
-
- const DisplayDevice& ref = *display;
- mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, ref); });
- result.append("\n");
- }
+ dumpHwcLayersMinidumpLocked(result);
{
DumpArgs plannerArgs;
@@ -5657,15 +5514,8 @@
reply->writeInt32(0);
reply->writeInt32(mDebugDisableHWC);
return NO_ERROR;
- case 1013: {
- const auto display = getDefaultDisplayDevice();
- if (!display) {
- return NAME_NOT_FOUND;
- }
-
- reply->writeInt32(display->getPageFlipCount());
- return NO_ERROR;
- }
+ case 1013: // Unused.
+ return NAME_NOT_FOUND;
case 1014: {
Mutex::Autolock _l(mStateLock);
// daltonize
@@ -5788,7 +5638,7 @@
mScheduler
->schedule([&]() FTL_FAKE_GUARD(mStateLock) {
mLayerTracing.notify(true /* visibleRegionDirty */,
- startingTime, mLastCommittedVsyncId);
+ startingTime, mLastCommittedVsyncId.value);
})
.wait();
}
@@ -6484,7 +6334,7 @@
return;
}
- sp<Layer> p = layer;
+ auto p = sp<Layer>::fromExisting(layer);
while (p != nullptr) {
if (excludeLayers.count(p) != 0) {
return;
@@ -6549,8 +6399,13 @@
1 /* layerCount */, usage, "screenshot");
const status_t bufferStatus = buffer->initCheck();
- LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d",
- bufferStatus);
+ if (bufferStatus != OK) {
+ // Animations may end up being really janky, but don't crash here.
+ // Otherwise an irreponsible process may cause an SF crash by allocating
+ // too much.
+ ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus);
+ return ftl::yield<FenceResult>(base::unexpected(bufferStatus)).share();
+ }
const std::shared_ptr<renderengine::ExternalTexture> texture = std::make_shared<
renderengine::impl::ExternalTexture>(buffer, getRenderEngine(),
renderengine::impl::ExternalTexture::Usage::
@@ -7082,7 +6937,7 @@
return calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
}
-void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state, int64_t vsyncId) {
+void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state, VsyncId vsyncId) {
sp<Layer> layer = state.layer.promote();
if (!layer) {
ALOGD("Layer was destroyed soon after creation %p", state.layer.unsafe_get());
@@ -7113,7 +6968,7 @@
layer->updateTransformHint(mActiveDisplayTransformHint);
if (mTransactionTracing) {
- mTransactionTracing->onLayerAddedToDrawingState(layer->getSequence(), vsyncId);
+ mTransactionTracing->onLayerAddedToDrawingState(layer->getSequence(), vsyncId.value);
}
mInterceptor->saveSurfaceCreation(layer);
}
@@ -7198,7 +7053,46 @@
return buffer;
}
-bool SurfaceFlinger::commitCreatedLayers(int64_t vsyncId) {
+bool SurfaceFlinger::commitMirrorDisplays(VsyncId vsyncId) {
+ std::vector<MirrorDisplayState> mirrorDisplays;
+ {
+ std::scoped_lock<std::mutex> lock(mMirrorDisplayLock);
+ mirrorDisplays = std::move(mMirrorDisplays);
+ mMirrorDisplays.clear();
+ if (mirrorDisplays.size() == 0) {
+ return false;
+ }
+ }
+
+ sp<IBinder> unused;
+ for (const auto& mirrorDisplay : mirrorDisplays) {
+ // Set mirror layer's default layer stack to -1 so it doesn't end up rendered on a display
+ // accidentally.
+ sp<Layer> rootMirrorLayer = Layer::fromHandle(mirrorDisplay.rootHandle).promote();
+ rootMirrorLayer->setLayerStack(ui::LayerStack::fromValue(-1));
+ for (const auto& layer : mDrawingState.layersSortedByZ) {
+ if (layer->getLayerStack() != mirrorDisplay.layerStack ||
+ layer->isInternalDisplayOverlay()) {
+ continue;
+ }
+
+ LayerCreationArgs mirrorArgs(this, mirrorDisplay.client, "MirrorLayerParent",
+ ISurfaceComposerClient::eNoColorFill,
+ gui::LayerMetadata());
+ sp<Layer> childMirror;
+ createEffectLayer(mirrorArgs, &unused, &childMirror);
+ childMirror->setClonedChild(layer->createClone());
+ if (mTransactionTracing) {
+ mTransactionTracing->onLayerAddedToDrawingState(childMirror->getSequence(),
+ vsyncId.value);
+ }
+ childMirror->reparent(mirrorDisplay.rootHandle);
+ }
+ }
+ return true;
+}
+
+bool SurfaceFlinger::commitCreatedLayers(VsyncId vsyncId) {
std::vector<LayerCreatedState> createdLayers;
{
std::scoped_lock<std::mutex> lock(mCreatedLayersLock);
@@ -7244,7 +7138,7 @@
}
binder::Status SurfaceComposerAIDL::createConnection(sp<gui::ISurfaceComposerClient>* outClient) {
- const sp<Client> client = new Client(mFlinger);
+ const sp<Client> client = sp<Client>::make(mFlinger);
if (client->initCheck() == NO_ERROR) {
*outClient = client;
return binder::Status::ok();
@@ -7285,20 +7179,6 @@
return binder::Status::ok();
}
-binder::Status SurfaceComposerAIDL::getPrimaryPhysicalDisplayId(int64_t* outDisplayId) {
- status_t status = checkAccessPermission();
- if (status != OK) {
- return binderStatusFromStatusT(status);
- }
-
- PhysicalDisplayId id;
- status = mFlinger->getPrimaryPhysicalDisplayId(&id);
- if (status == NO_ERROR) {
- *outDisplayId = id.value;
- }
- return binderStatusFromStatusT(status);
-}
-
binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId,
sp<IBinder>* outDisplay) {
const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
@@ -7547,40 +7427,6 @@
return binderStatusFromStatusT(status);
}
-binder::Status SurfaceComposerAIDL::clearAnimationFrameStats() {
- status_t status = checkAccessPermission();
- if (status == OK) {
- status = mFlinger->clearAnimationFrameStats();
- }
- return binderStatusFromStatusT(status);
-}
-
-binder::Status SurfaceComposerAIDL::getAnimationFrameStats(gui::FrameStats* outStats) {
- status_t status = checkAccessPermission();
- if (status != OK) {
- return binderStatusFromStatusT(status);
- }
-
- FrameStats stats;
- status = mFlinger->getAnimationFrameStats(&stats);
- if (status == NO_ERROR) {
- outStats->refreshPeriodNano = stats.refreshPeriodNano;
- outStats->desiredPresentTimesNano.reserve(stats.desiredPresentTimesNano.size());
- for (const auto& t : stats.desiredPresentTimesNano) {
- outStats->desiredPresentTimesNano.push_back(t);
- }
- outStats->actualPresentTimesNano.reserve(stats.actualPresentTimesNano.size());
- for (const auto& t : stats.actualPresentTimesNano) {
- outStats->actualPresentTimesNano.push_back(t);
- }
- outStats->frameReadyTimesNano.reserve(stats.frameReadyTimesNano.size());
- for (const auto& t : stats.frameReadyTimesNano) {
- outStats->frameReadyTimesNano.push_back(t);
- }
- }
- return binderStatusFromStatusT(status);
-}
-
binder::Status SurfaceComposerAIDL::overrideHdrTypes(const sp<IBinder>& display,
const std::vector<int32_t>& hdrTypes) {
// overrideHdrTypes is used by CTS tests, which acquire the necessary
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7d23c3c..4d4d263 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -55,6 +55,8 @@
#include <compositionengine/FenceResult.h>
#include <compositionengine/OutputColorSetting.h>
#include <scheduler/Fps.h>
+#include <scheduler/PresentLatencyTracker.h>
+#include <scheduler/Time.h>
#include "ClientCache.h"
#include "DisplayDevice.h"
@@ -65,6 +67,7 @@
#include "FlagManager.h"
#include "FrameTracker.h"
#include "LayerVector.h"
+#include "LocklessQueue.h"
#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/RefreshRateStats.h"
#include "Scheduler/Scheduler.h"
@@ -94,12 +97,12 @@
#include <utility>
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+#include "Client.h"
using namespace android::surfaceflinger;
namespace android {
-class Client;
class EventThread;
class FlagManager;
class FpsReporter;
@@ -168,20 +171,6 @@
using DisplayColorSetting = compositionengine::OutputColorSetting;
-struct SurfaceFlingerBE {
- // Only accessed from the main thread.
- struct CompositePresentTime {
- nsecs_t composite = -1;
- std::shared_ptr<FenceTime> display = FenceTime::NO_FENCE;
- };
- std::queue<CompositePresentTime> mCompositePresentTimes;
-
- static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
- nsecs_t mFrameBuckets[NUM_BUCKETS] = {};
- nsecs_t mTotalTime = 0;
- std::atomic<nsecs_t> mLastSwapTime = 0;
-};
-
class SurfaceFlinger : public BnSurfaceComposer,
public PriorityDumper,
private IBinder::DeathRecipient,
@@ -202,29 +191,6 @@
static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; }
- // This is the phase offset in nanoseconds of the software vsync event
- // relative to the vsync event reported by HWComposer. The software vsync
- // event is when SurfaceFlinger and Choreographer-based applications run each
- // frame.
- //
- // This phase offset allows adjustment of the minimum latency from application
- // wake-up time (by Choreographer) to the time at which the resulting window
- // image is displayed. This value may be either positive (after the HW vsync)
- // or negative (before the HW vsync). Setting it to 0 will result in a lower
- // latency bound of two vsync periods because the app and SurfaceFlinger
- // will run just after the HW vsync. Setting it to a positive number will
- // result in the minimum latency being:
- //
- // (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD))
- //
- // Note that reducing this latency makes it more likely for the applications
- // to not have their window content image ready in time. When this happens
- // the latency will end up being an additional vsync period, and animations
- // will hiccup. Therefore, this latency should be tuned somewhat
- // conservatively (or at least with awareness of the trade-off being made).
- static int64_t vsyncPhaseOffsetNs;
- static int64_t sfVsyncPhaseOffsetNs;
-
// If fences from sync Framework are supported.
static bool hasSyncFramework;
@@ -278,9 +244,6 @@
// starts SurfaceFlinger main loop in the current thread
void run() ANDROID_API;
- SurfaceFlingerBE& getBE() { return mBE; }
- const SurfaceFlingerBE& getBE() const { return mBE; }
-
// Indicates frame activity, i.e. whether commit and/or composite is taking place.
enum class FrameHint { kNone, kActive };
@@ -391,10 +354,6 @@
using DumpArgs = Vector<String16>;
using Dumper = std::function<void(const DumpArgs&, bool asProto, std::string&)>;
- // This value is specified in number of frames. Log frame stats at most
- // every half hour.
- enum { LOG_FRAME_STATS_PERIOD = 30*60*60 };
-
class State {
public:
explicit State(LayerVector::StateSet set) : stateSet(set), layersSortedByZ(set) {}
@@ -529,7 +488,6 @@
Mutex::Autolock lock(mStateLock);
return getPhysicalDisplayIdsLocked();
}
- status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const EXCLUDES(mStateLock);
sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const;
status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
@@ -567,8 +525,6 @@
void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on);
void setGameContentType(const sp<IBinder>& displayToken, bool on);
void setPowerMode(const sp<IBinder>& displayToken, int mode);
- status_t clearAnimationFrameStats();
- status_t getAnimationFrameStats(FrameStats* outStats) const;
status_t overrideHdrTypes(const sp<IBinder>& displayToken,
const std::vector<ui::Hdr>& hdrTypes);
status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success);
@@ -657,11 +613,11 @@
// Commits transactions for layers and displays. Returns whether any state has been invalidated,
// i.e. whether a frame should be composited for each display.
- bool commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) override;
+ bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) override;
// Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition
// via RenderEngine and the Composer HAL, respectively.
- void composite(nsecs_t frameTime, int64_t vsyncId) override;
+ void composite(TimePoint frameTime, VsyncId) override;
// Samples the composited frame via RegionSamplingThread.
void sample() override;
@@ -753,22 +709,15 @@
const std::vector<ListenerCallbacks>& listenerCallbacks,
int originPid, int originUid, uint64_t transactionId)
REQUIRES(mStateLock);
- // flush pending transaction that was presented after desiredPresentTime.
- bool flushTransactionQueues(int64_t vsyncId);
+ // Flush pending transactions that were presented after desiredPresentTime.
+ bool flushTransactionQueues(VsyncId) REQUIRES(kMainThreadContext);
// Returns true if there is at least one transaction that needs to be flushed
bool transactionFlushNeeded();
int flushPendingTransactionQueues(
std::vector<TransactionState>& transactions,
std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
- std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions,
- bool tryApplyUnsignaled) REQUIRES(mStateLock, mQueueLock);
-
- int flushUnsignaledPendingTransactionQueues(
- std::vector<TransactionState>& transactions,
- std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
- std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions)
- REQUIRES(mStateLock, mQueueLock);
+ bool tryApplyUnsignaled) REQUIRES(mStateLock) REQUIRES(kMainThreadContext);
uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&,
int64_t desiredPresentTime, bool isAutoTimestamp,
@@ -792,23 +741,24 @@
Ready,
ReadyUnsignaled,
};
- TransactionReadiness transactionIsReadyToBeApplied(TransactionState& state,
- const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
- uid_t originUid, const Vector<ComposerState>& states,
- const std::unordered_map<
- sp<IBinder>, uint64_t, SpHash<IBinder>>& bufferLayersReadyToPresent,
- size_t totalTXapplied, bool tryApplyUnsignaled) const REQUIRES(mStateLock);
+ TransactionReadiness transactionIsReadyToBeApplied(
+ TransactionState&, const FrameTimelineInfo&, bool isAutoTimestamp,
+ TimePoint desiredPresentTime, uid_t originUid, const Vector<ComposerState>&,
+ const std::unordered_map<sp<IBinder>, uint64_t, SpHash<IBinder>>&
+ bufferLayersReadyToPresent,
+ size_t totalTXapplied, bool tryApplyUnsignaled) const REQUIRES(mStateLock)
+ REQUIRES(kMainThreadContext);
+
static LatchUnsignaledConfig getLatchUnsignaledConfig();
bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&, size_t numStates,
size_t totalTXapplied) const;
- bool stopTransactionProcessing(const std::unordered_set<sp<IBinder>, SpHash<IBinder>>&
- applyTokensWithUnsignaledTransactions) const;
- bool applyTransactions(std::vector<TransactionState>& transactions, int64_t vsyncId)
+ bool applyTransactions(std::vector<TransactionState>& transactions, VsyncId)
REQUIRES(mStateLock);
uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
REQUIRES(mStateLock);
- bool frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const;
+ bool frameIsEarly(TimePoint expectedPresentTime, VsyncId) const;
+
/*
* Layer management
*/
@@ -823,12 +773,12 @@
status_t createEffectLayer(const LayerCreationArgs& args, sp<IBinder>* outHandle,
sp<Layer>* outLayer);
- status_t createContainerLayer(const LayerCreationArgs& args, sp<IBinder>* outHandle,
- sp<Layer>* outLayer);
-
status_t mirrorLayer(const LayerCreationArgs& args, const sp<IBinder>& mirrorFromHandle,
sp<IBinder>* outHandle, int32_t* outLayerId);
+ status_t mirrorDisplay(DisplayId displayId, const LayerCreationArgs& args,
+ sp<IBinder>* outHandle, int32_t* outLayerId);
+
// called when all clients have released all their references to
// this layer meaning it is entirely safe to destroy all
// resources associated to this layer.
@@ -953,12 +903,7 @@
/*
* Compositing
*/
- void postComposition();
-
- // Returns the composite-to-present latency of the latest presented frame.
- nsecs_t trackPresentLatency(nsecs_t compositeTime, std::shared_ptr<FenceTime> presentFenceTime);
-
- void postFrame() REQUIRES(kMainThreadContext);
+ void postComposition() REQUIRES(kMainThreadContext);
/*
* Display management
@@ -993,7 +938,7 @@
using FenceTimePtr = std::shared_ptr<FenceTime>;
- const FenceTimePtr& getPreviousPresentFence(nsecs_t frameTime, Period)
+ const FenceTimePtr& getPreviousPresentFence(TimePoint frameTime, Period)
REQUIRES(kMainThreadContext);
// Blocks the thread waiting for up to graceTimeMs in case the fence is about to signal.
@@ -1001,7 +946,7 @@
// Calculates the expected present time for this frame. For negative offsets, performs a
// correction using the predicted vsync for the next frame instead.
- TimePoint calculateExpectedPresentTime(nsecs_t frameTime) const;
+ TimePoint calculateExpectedPresentTime(TimePoint frameTime) const;
/*
* Display identification
@@ -1051,6 +996,7 @@
* Debugging & dumpsys
*/
void dumpAllLocked(const DumpArgs& args, std::string& result) const REQUIRES(mStateLock);
+ void dumpHwcLayersMinidumpLocked(std::string& result) const REQUIRES(mStateLock);
void appendSfConfigString(std::string& result) const;
void listLayersLocked(std::string& result) const;
@@ -1058,10 +1004,9 @@
void clearStatsLocked(const DumpArgs& args, std::string& result);
void dumpTimeStats(const DumpArgs& args, bool asProto, std::string& result) const;
void dumpFrameTimeline(const DumpArgs& args, std::string& result) const;
- void logFrameStats() REQUIRES(kMainThreadContext);
+ void logFrameStats(TimePoint now) REQUIRES(kMainThreadContext);
void dumpVSync(std::string& result) const REQUIRES(mStateLock);
- void dumpStaticScreenStats(std::string& result) const;
void dumpCompositionDisplays(std::string& result) const REQUIRES(mStateLock);
void dumpDisplays(std::string& result) const REQUIRES(mStateLock);
@@ -1098,7 +1043,7 @@
status_t CheckTransactCodeCredentials(uint32_t code);
// Add transaction to the Transaction Queue
- void queueTransaction(TransactionState& state) EXCLUDES(mQueueLock);
+ void queueTransaction(TransactionState& state);
void waitForSynchronousTransaction(const CountDownLatch& transactionCommittedSignal);
void signalSynchronousTransactions(const uint32_t flag);
@@ -1134,7 +1079,6 @@
State mCurrentState{LayerVector::StateSet::Current};
std::atomic<int32_t> mTransactionFlags = 0;
std::vector<std::shared_ptr<CountDownLatch>> mTransactionCommittedSignals;
- bool mAnimTransactionPending = false;
std::atomic<uint32_t> mUniqueTransactionId = 1;
SortedVector<sp<Layer>> mLayersPendingRemoval;
@@ -1182,8 +1126,6 @@
bool mSomeDataspaceChanged = false;
bool mForceTransactionDisplayChange = false;
- bool mAnimCompositionPending = false;
-
// Tracks layers that have pending frames which are candidates for being
// latched.
std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithQueuedFrames;
@@ -1240,7 +1182,7 @@
const std::unique_ptr<FrameTracer> mFrameTracer;
const std::unique_ptr<frametimeline::FrameTimeline> mFrameTimeline;
- int64_t mLastCommittedVsyncId = -1;
+ VsyncId mLastCommittedVsyncId;
// If blurs should be enabled on this device.
bool mSupportsBlur = false;
@@ -1252,9 +1194,6 @@
TransactionCallbackInvoker mTransactionCallbackInvoker;
- // Thread-safe.
- FrameTracker mAnimFrameTracker;
-
// We maintain a pool of pre-generated texture names to hand out to avoid
// layer creation needing to run on the main thread (which it would
// otherwise need to do to access RenderEngine).
@@ -1262,18 +1201,10 @@
uint32_t mTexturePoolSize = 0;
std::vector<uint32_t> mTexturePool;
- mutable Mutex mQueueLock;
- Condition mTransactionQueueCV;
std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash>
- mPendingTransactionQueues GUARDED_BY(mQueueLock);
- std::deque<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock);
- /*
- * Feature prototyping
- */
-
- // Static screen stats
- bool mHasPoweredOff = false;
-
+ mPendingTransactionQueues;
+ LocklessQueue<TransactionState> mLocklessTransactionQueue;
+ std::atomic<size_t> mPendingTransactionCount = 0;
std::atomic<size_t> mNumLayers = 0;
// to linkToDeath
@@ -1301,7 +1232,6 @@
ui::Dataspace mColorSpaceAgnosticDataspace;
float mDimmingRatio = -1.f;
- SurfaceFlingerBE mBE;
std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
// mMaxRenderTargetSize is only set once in init() so it doesn't need to be protected by
// any mutex.
@@ -1325,6 +1255,7 @@
sp<VsyncModulator> mVsyncModulator;
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
+ scheduler::PresentLatencyTracker mPresentLatencyTracker GUARDED_BY(kMainThreadContext);
struct FenceWithFenceTime {
sp<Fence> fence = Fence::NO_FENCE;
@@ -1332,8 +1263,9 @@
};
std::array<FenceWithFenceTime, 2> mPreviousPresentFences;
- std::atomic<nsecs_t> mExpectedPresentTime = 0;
- nsecs_t mScheduledPresentTime = 0;
+ TimePoint mScheduledPresentTime GUARDED_BY(kMainThreadContext);
+ TimePoint mExpectedPresentTime GUARDED_BY(kMainThreadContext);
+
hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
hal::Vsync mLastHWCVsyncState = hal::Vsync::DISABLE;
@@ -1387,9 +1319,21 @@
// A temporay pool that store the created layers and will be added to current state in main
// thread.
std::vector<LayerCreatedState> mCreatedLayers GUARDED_BY(mCreatedLayersLock);
- bool commitCreatedLayers(int64_t vsyncId);
- void handleLayerCreatedLocked(const LayerCreatedState& state, int64_t vsyncId)
- REQUIRES(mStateLock);
+ bool commitCreatedLayers(VsyncId);
+ void handleLayerCreatedLocked(const LayerCreatedState&, VsyncId) REQUIRES(mStateLock);
+
+ mutable std::mutex mMirrorDisplayLock;
+ struct MirrorDisplayState {
+ MirrorDisplayState(ui::LayerStack layerStack, sp<IBinder>& rootHandle,
+ const sp<Client>& client)
+ : layerStack(layerStack), rootHandle(rootHandle), client(client) {}
+
+ ui::LayerStack layerStack;
+ sp<IBinder> rootHandle;
+ const sp<Client> client;
+ };
+ std::vector<MirrorDisplayState> mMirrorDisplays GUARDED_BY(mMirrorDisplayLock);
+ bool commitMirrorDisplays(VsyncId);
std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint;
@@ -1434,7 +1378,6 @@
sp<IBinder>* outDisplay) override;
binder::Status destroyDisplay(const sp<IBinder>& display) override;
binder::Status getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) override;
- binder::Status getPrimaryPhysicalDisplayId(int64_t* outDisplayId) override;
binder::Status getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) override;
binder::Status setPowerMode(const sp<IBinder>& display, int mode) override;
binder::Status getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) override;
@@ -1459,8 +1402,15 @@
binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override;
binder::Status captureLayers(const LayerCaptureArgs&,
const sp<IScreenCaptureListener>&) override;
- binder::Status clearAnimationFrameStats() override;
- binder::Status getAnimationFrameStats(gui::FrameStats* outStats) override;
+
+ // TODO(b/239076119): Remove deprecated AIDL.
+ [[deprecated]] binder::Status clearAnimationFrameStats() override {
+ return binder::Status::ok();
+ }
+ [[deprecated]] binder::Status getAnimationFrameStats(gui::FrameStats*) override {
+ return binder::Status::ok();
+ }
+
binder::Status overrideHdrTypes(const sp<IBinder>& display,
const std::vector<int32_t>& hdrTypes) override;
binder::Status onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) override;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 2399a39..5c96f35 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -23,7 +23,6 @@
#include <ui/GraphicBuffer.h>
#include "BufferStateLayer.h"
-#include "ContainerLayer.h"
#include "DisplayDevice.h"
#include "EffectLayer.h"
#include "FrameTracer/FrameTracer.h"
@@ -57,22 +56,22 @@
}
sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor() {
- return new android::impl::SurfaceInterceptor();
+ return sp<android::impl::SurfaceInterceptor>::make();
}
sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread(
bool timestampPropertyValue) {
- return new StartPropertySetThread(timestampPropertyValue);
+ return sp<StartPropertySetThread>::make(timestampPropertyValue);
}
sp<DisplayDevice> DefaultFactory::createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) {
- return new DisplayDevice(creationArgs);
+ return sp<DisplayDevice>::make(creationArgs);
}
sp<GraphicBuffer> DefaultFactory::createGraphicBuffer(uint32_t width, uint32_t height,
PixelFormat format, uint32_t layerCount,
uint64_t usage, std::string requestorName) {
- return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+ return sp<GraphicBuffer>::make(width, height, format, layerCount, usage, requestorName);
}
void DefaultFactory::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
@@ -90,16 +89,12 @@
return compositionengine::impl::createCompositionEngine();
}
-sp<ContainerLayer> DefaultFactory::createContainerLayer(const LayerCreationArgs& args) {
- return new ContainerLayer(args);
-}
-
sp<BufferStateLayer> DefaultFactory::createBufferStateLayer(const LayerCreationArgs& args) {
- return new BufferStateLayer(args);
+ return sp<BufferStateLayer>::make(args);
}
sp<EffectLayer> DefaultFactory::createEffectLayer(const LayerCreationArgs& args) {
- return new EffectLayer(args);
+ return sp<EffectLayer>::make(args);
}
std::unique_ptr<FrameTracer> DefaultFactory::createFrameTracer() {
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 4000e09..8d00379 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -43,7 +43,6 @@
std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override;
sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override;
sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) override;
- sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override;
std::unique_ptr<FrameTracer> createFrameTracer() override;
std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) override;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index 3997b04..7bd6cf6 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -26,7 +26,7 @@
sp<SurfaceFlinger> createSurfaceFlinger() {
static DefaultFactory factory;
- return new SurfaceFlinger(factory);
+ return sp<SurfaceFlinger>::make(factory);
}
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 77a75c4..291838f 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -32,7 +32,6 @@
class BufferLayerConsumer;
class BufferStateLayer;
-class ContainerLayer;
class DisplayDevice;
class EffectLayer;
class FrameTracer;
@@ -93,7 +92,6 @@
virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
virtual sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) = 0;
- virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
virtual std::unique_ptr<FrameTracer> createFrameTracer() = 0;
virtual std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) = 0;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 0782fef..66691c2 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -46,7 +46,7 @@
std::scoped_lock lock(mListenersMutex);
- asBinder->linkToDeath(this);
+ asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
listener->onToggled(mEnabled); // notifies of current state
@@ -115,8 +115,9 @@
ATRACE_CALL();
for (const auto& l : layers) {
l->traverseInZOrder(LayerVector::StateSet::Drawing, [this](Layer* layer) {
- addSurfaceCreationLocked(createTraceIncrementLocked(), layer);
- addInitialSurfaceStateLocked(createTraceIncrementLocked(), layer);
+ addSurfaceCreationLocked(createTraceIncrementLocked(), sp<Layer>::fromExisting(layer));
+ addInitialSurfaceStateLocked(createTraceIncrementLocked(),
+ sp<Layer>::fromExisting(layer));
});
}
}
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index afa3e50..566d553 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -89,6 +89,9 @@
LayersTraceFileProto fileProto;
fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
+ auto timeOffsetNs = static_cast<std::uint64_t>(systemTime(SYSTEM_TIME_REALTIME) -
+ systemTime(SYSTEM_TIME_MONOTONIC));
+ fileProto.set_real_to_elapsed_time_offset_nanos(timeOffsetNs);
return fileProto;
}
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 65918f6..77dec6f 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -457,9 +457,9 @@
layer.parentSurfaceControlForChild = nullptr;
} else {
layer.parentSurfaceControlForChild =
- new SurfaceControl(SurfaceComposerClient::getDefault(),
- mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
- static_cast<int32_t>(layerId));
+ sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(),
+ mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
+ static_cast<int32_t>(layerId));
}
}
if (proto.what() & layer_state_t::eRelativeLayerChanged) {
@@ -468,9 +468,9 @@
layer.relativeLayerSurfaceControl = nullptr;
} else {
layer.relativeLayerSurfaceControl =
- new SurfaceControl(SurfaceComposerClient::getDefault(),
- mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
- static_cast<int32_t>(layerId));
+ sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(),
+ mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
+ static_cast<int32_t>(layerId));
}
layer.z = proto.z();
}
@@ -502,7 +502,7 @@
inputInfo.touchableRegionCropHandle =
mMapper->getLayerHandle(static_cast<int32_t>(layerId));
} else {
- inputInfo.touchableRegionCropHandle = nullptr;
+ inputInfo.touchableRegionCropHandle = wp<IBinder>();
}
layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index af0594e..cb5320b 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -134,6 +134,9 @@
proto::TransactionTraceFile proto;
proto.set_magic_number(uint64_t(proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_H) << 32 |
proto::TransactionTraceFile_MagicNumber_MAGIC_NUMBER_L);
+ auto timeOffsetNs = static_cast<std::uint64_t>(systemTime(SYSTEM_TIME_REALTIME) -
+ systemTime(SYSTEM_TIME_MONOTONIC));
+ proto.set_real_to_elapsed_time_offset_nanos(timeOffsetNs);
return proto;
}
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index c4b1b0f..312d4ab 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -48,23 +48,23 @@
}
sp<SurfaceInterceptor> createSurfaceInterceptor() override {
- return new android::impl::SurfaceInterceptor();
+ return sp<android::impl::SurfaceInterceptor>::make();
}
sp<StartPropertySetThread> createStartPropertySetThread(
bool /* timestampPropertyValue */) override {
- return nullptr;
+ return sp<StartPropertySetThread>();
}
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& /* creationArgs */) override {
- return nullptr;
+ return sp<DisplayDevice>();
}
sp<GraphicBuffer> createGraphicBuffer(uint32_t /* width */, uint32_t /* height */,
PixelFormat /* format */, uint32_t /* layerCount */,
uint64_t /* usage */,
std::string /* requestorName */) override {
- return nullptr;
+ return sp<GraphicBuffer>();
}
void createBufferQueue(sp<IGraphicBufferProducer>* /* outProducer */,
@@ -80,16 +80,12 @@
return compositionengine::impl::createCompositionEngine();
}
- sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) {
- return sp<ContainerLayer>::make(args);
- }
-
sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) {
- return new BufferStateLayer(args);
+ return sp<BufferStateLayer>::make(args);
}
sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) {
- return new EffectLayer(args);
+ return sp<EffectLayer>::make(args);
}
std::unique_ptr<FrameTracer> createFrameTracer() override {
@@ -178,7 +174,7 @@
}
Factory mFactory;
- sp<MockSurfaceFlinger> flinger = new MockSurfaceFlinger(mFactory);
+ sp<MockSurfaceFlinger> flinger = sp<MockSurfaceFlinger>::make(mFactory);
TestableSurfaceFlinger mFlinger(flinger);
mFlinger.setupRenderEngine(
std::make_unique<testing::NiceMock<renderengine::mock::RenderEngine>>());
@@ -205,8 +201,6 @@
TraceGenFlingerDataMapper* dataMapper = mapper.get();
TransactionProtoParser parser(std::move(mapper));
- nsecs_t frameTime;
- int64_t vsyncId;
ALOGD("Generating %d transactions...", traceFile.entry_size());
for (int i = 0; i < traceFile.entry_size(); i++) {
proto::TransactionTraceEntry entry = traceFile.entry(i);
@@ -260,8 +254,8 @@
transaction.listenerCallbacks, transaction.id);
}
- frameTime = entry.elapsed_realtime_nanos();
- vsyncId = entry.vsync_id();
+ const auto frameTime = TimePoint::fromNs(entry.elapsed_realtime_nanos());
+ const auto vsyncId = VsyncId{entry.vsync_id()};
mFlinger.commit(frameTime, vsyncId);
for (int j = 0; j < entry.removed_layer_handles_size(); j++) {
@@ -275,4 +269,4 @@
return true;
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index d2c2e29..e5de759 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -178,8 +178,8 @@
return NO_ERROR;
}
-void TransactionCallbackInvoker::addPresentFence(const sp<Fence>& presentFence) {
- mPresentFence = presentFence;
+void TransactionCallbackInvoker::addPresentFence(sp<Fence> presentFence) {
+ mPresentFence = std::move(presentFence);
}
void TransactionCallbackInvoker::sendCallbacks(bool onCommitOnly) {
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 81d79f0..59abe33 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -70,7 +70,7 @@
status_t registerUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
void addEmptyTransaction(const ListenerCallbacks& listenerCallbacks);
- void addPresentFence(const sp<Fence>& presentFence);
+ void addPresentFence(sp<Fence>);
void sendCallbacks(bool onCommitOnly);
void clearCompletedTransactions() {
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index bbfeac1..61f0fa6 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -98,7 +98,6 @@
int originUid;
uint64_t id;
std::shared_ptr<CountDownLatch> transactionCommittedSignal;
- int64_t queueTime = 0;
bool sentFenceTimeoutWarning = false;
};
diff --git a/services/surfaceflinger/TunnelModeEnabledReporter.cpp b/services/surfaceflinger/TunnelModeEnabledReporter.cpp
index 4497caf..bc9b870 100644
--- a/services/surfaceflinger/TunnelModeEnabledReporter.cpp
+++ b/services/surfaceflinger/TunnelModeEnabledReporter.cpp
@@ -59,7 +59,7 @@
void TunnelModeEnabledReporter::addListener(const sp<gui::ITunnelModeEnabledListener>& listener) {
sp<IBinder> asBinder = IInterface::asBinder(listener);
- asBinder->linkToDeath(this);
+ asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
bool tunnelModeEnabled = false;
{
std::scoped_lock lock(mMutex);
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 4a8f157..a1313e3 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -62,7 +62,7 @@
void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) {
sp<IBinder> asBinder = IInterface::asBinder(listener);
- asBinder->linkToDeath(this);
+ asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
std::scoped_lock lock(mListenersMutex);
mWindowInfosListeners.try_emplace(asBinder, std::move(listener));
@@ -73,7 +73,7 @@
sp<IBinder> asBinder = IInterface::asBinder(listener);
std::scoped_lock lock(mListenersMutex);
- asBinder->unlinkToDeath(this);
+ asBinder->unlinkToDeath(sp<DeathRecipient>::fromExisting(this));
mWindowInfosListeners.erase(asBinder);
}
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index a605a2f..fae9165 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -116,7 +116,8 @@
class DisplayHardwareFuzzer {
public:
DisplayHardwareFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) {
- mPhysicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value();
+ mPhysicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value_or(
+ PhysicalDisplayId::fromPort(mFdp.ConsumeIntegral<uint8_t>()));
};
void process();
@@ -480,8 +481,8 @@
BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
sp<FramebufferSurface> surface =
- new FramebufferSurface(mHwc, mPhysicalDisplayId, bqConsumer, getFuzzedSize() /*size*/,
- getFuzzedSize() /*maxSize*/);
+ sp<FramebufferSurface>::make(mHwc, mPhysicalDisplayId, bqConsumer,
+ getFuzzedSize() /*size*/, getFuzzedSize() /*maxSize*/);
surface->beginFrame(mFdp.ConsumeBool());
surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes));
@@ -497,15 +498,15 @@
DisplayIdGenerator<HalVirtualDisplayId> mGenerator;
VirtualDisplayId VirtualDisplayId = mGenerator.generateId().value();
- sp<SurfaceComposerClient> mClient = new SurfaceComposerClient();
+ sp<SurfaceComposerClient> mClient = sp<SurfaceComposerClient>::make();
sp<SurfaceControl> mSurfaceControl =
mClient->createSurface(String8("TestSurface"), 100, 100, PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceBufferState,
/*parent*/ nullptr);
- sp<BLASTBufferQueue> mBlastBufferQueueAdapter =
- new BLASTBufferQueue("TestBLASTBufferQueue", mSurfaceControl, 100, 100,
- PIXEL_FORMAT_RGBA_8888);
+ auto mBlastBufferQueueAdapter =
+ sp<BLASTBufferQueue>::make("TestBLASTBufferQueue", mSurfaceControl, 100, 100,
+ PIXEL_FORMAT_RGBA_8888);
sp<IGraphicBufferProducer> sink = mBlastBufferQueueAdapter->getIGraphicBufferProducer();
sp<IGraphicBufferProducer> bqProducer = mBlastBufferQueueAdapter->getIGraphicBufferProducer();
@@ -513,9 +514,9 @@
BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
BufferQueue::createBufferQueue(&sink, &bqConsumer);
- sp<VirtualDisplaySurface> surface =
- new VirtualDisplaySurface(mHwc, VirtualDisplayId, sink, bqProducer, bqConsumer,
- mFdp.ConsumeRandomLengthString().c_str() /*name*/);
+ auto surface =
+ sp<VirtualDisplaySurface>::make(mHwc, VirtualDisplayId, sink, bqProducer, bqConsumer,
+ mFdp.ConsumeRandomLengthString().c_str() /*name*/);
surface->beginFrame(mFdp.ConsumeBool());
surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes));
@@ -565,7 +566,7 @@
mHwc.getLayerReleaseFence(halDisplayID, layer);
- mHwc.setOutputBuffer(halVirtualDisplayId, sp<Fence>::make().get(), sp<GraphicBuffer>::make());
+ mHwc.setOutputBuffer(halVirtualDisplayId, sp<Fence>::make(), sp<GraphicBuffer>::make());
mHwc.clearReleaseFences(halDisplayID);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index 8e60247..28b875a 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -103,7 +103,7 @@
class SurfaceFlingerFuzzer {
public:
SurfaceFlingerFuzzer(const uint8_t *data, size_t size) : mFdp(data, size) {
- mFlinger = mTestableFlinger.flinger();
+ mFlinger = sp<SurfaceFlinger>::fromExisting(mTestableFlinger.flinger());
};
void process(const uint8_t *data, size_t size);
@@ -244,7 +244,6 @@
setDisplayStateLocked();
setTransactionState();
- mTestableFlinger.flushTransactionQueues();
onTransact(data, size);
}
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 3338da0..4c649f3 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -31,7 +31,6 @@
#include <ui/DynamicDisplayInfo.h>
#include "BufferStateLayer.h"
-#include "ContainerLayer.h"
#include "DisplayDevice.h"
#include "DisplayHardware/ComposerHal.h"
#include "EffectLayer.h"
@@ -154,14 +153,22 @@
ui::PixelFormat::YCBCR_P010,
ui::PixelFormat::HSV_888};
-FloatRect getFuzzedFloatRect(FuzzedDataProvider *fdp) {
+inline VsyncId getFuzzedVsyncId(FuzzedDataProvider& fdp) {
+ return VsyncId{fdp.ConsumeIntegral<int64_t>()};
+}
+
+inline TimePoint getFuzzedTimePoint(FuzzedDataProvider& fdp) {
+ return TimePoint::fromNs(fdp.ConsumeIntegral<nsecs_t>());
+}
+
+inline FloatRect getFuzzedFloatRect(FuzzedDataProvider* fdp) {
return FloatRect(fdp->ConsumeFloatingPoint<float>() /*left*/,
fdp->ConsumeFloatingPoint<float>() /*right*/,
fdp->ConsumeFloatingPoint<float>() /*top*/,
fdp->ConsumeFloatingPoint<float>() /*bottom*/);
}
-HdrMetadata getFuzzedHdrMetadata(FuzzedDataProvider *fdp) {
+inline HdrMetadata getFuzzedHdrMetadata(FuzzedDataProvider* fdp) {
HdrMetadata hdrMetadata;
if (fdp->ConsumeBool()) {
hdrMetadata.cta8613.maxContentLightLevel = fdp->ConsumeFloatingPoint<float>();
@@ -271,8 +278,8 @@
private:
// ICompositor overrides:
- bool commit(nsecs_t, int64_t, nsecs_t) override { return false; }
- void composite(nsecs_t, int64_t) override {}
+ bool commit(TimePoint, VsyncId, TimePoint) override { return false; }
+ void composite(TimePoint, VsyncId) override {}
void sample() override {}
// MessageQueue overrides:
@@ -285,13 +292,18 @@
namespace surfaceflinger::test {
class Factory final : public surfaceflinger::Factory {
+ struct NoOpMessageQueue : android::impl::MessageQueue {
+ using android::impl::MessageQueue::MessageQueue;
+ void onFrameSignal(ICompositor&, VsyncId, TimePoint) override {}
+ };
+
public:
~Factory() = default;
- std::unique_ptr<HWComposer> createHWComposer(const std::string &) override { return nullptr; }
+ std::unique_ptr<HWComposer> createHWComposer(const std::string&) override { return nullptr; }
- std::unique_ptr<MessageQueue> createMessageQueue(ICompositor &compositor) {
- return std::make_unique<android::impl::MessageQueue>(compositor);
+ std::unique_ptr<MessageQueue> createMessageQueue(ICompositor& compositor) {
+ return std::make_unique<NoOpMessageQueue>(compositor);
}
std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
@@ -306,21 +318,21 @@
}
sp<SurfaceInterceptor> createSurfaceInterceptor() override {
- return new android::impl::SurfaceInterceptor();
+ return sp<android::impl::SurfaceInterceptor>::make();
}
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
- return new StartPropertySetThread(timestampPropertyValue);
+ return sp<StartPropertySetThread>::make(timestampPropertyValue);
}
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs &creationArgs) override {
- return new DisplayDevice(creationArgs);
+ return sp<DisplayDevice>::make(creationArgs);
}
sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
std::string requestorName) override {
- return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+ return sp<GraphicBuffer>::make(width, height, format, layerCount, usage, requestorName);
}
void createBufferQueue(sp<IGraphicBufferProducer> *outProducer,
@@ -348,11 +360,7 @@
}
sp<EffectLayer> createEffectLayer(const LayerCreationArgs &args) override {
- return new EffectLayer(args);
- }
-
- sp<ContainerLayer> createContainerLayer(const LayerCreationArgs &args) override {
- return new ContainerLayer(args);
+ return sp<EffectLayer>::make(args);
}
std::unique_ptr<FrameTracer> createFrameTracer() override {
@@ -430,15 +438,13 @@
mFlinger->clearStatsLocked(dumpArgs, result);
mFlinger->dumpTimeStats(dumpArgs, fdp->ConsumeBool(), result);
- FTL_FAKE_GUARD(kMainThreadContext, mFlinger->logFrameStats());
+ FTL_FAKE_GUARD(kMainThreadContext,
+ mFlinger->logFrameStats(TimePoint::fromNs(fdp->ConsumeIntegral<nsecs_t>())));
result = fdp->ConsumeRandomLengthString().c_str();
mFlinger->dumpFrameTimeline(dumpArgs, result);
result = fdp->ConsumeRandomLengthString().c_str();
- mFlinger->dumpStaticScreenStats(result);
-
- result = fdp->ConsumeRandomLengthString().c_str();
mFlinger->dumpRawDisplayIdentificationData(dumpArgs, result);
LayersProto layersProto = mFlinger->dumpDrawingStateProto(fdp->ConsumeIntegral<uint32_t>());
@@ -525,7 +531,7 @@
sp<IBinder> fuzzBoot(FuzzedDataProvider *fdp) {
mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(fdp->ConsumeBool());
- const sp<Client> client = new Client(mFlinger);
+ const sp<Client> client = sp<Client>::make(mFlinger);
DisplayIdGenerator<HalVirtualDisplayId> kGenerator;
HalVirtualDisplayId halVirtualDisplayId = kGenerator.generateId().value();
@@ -534,7 +540,9 @@
ui::PixelFormat pixelFormat{};
mFlinger->getHwComposer().allocateVirtualDisplay(halVirtualDisplayId, uiSize, &pixelFormat);
- PhysicalDisplayId physicalDisplayId = SurfaceComposerClient::getInternalDisplayId().value();
+ PhysicalDisplayId physicalDisplayId =
+ SurfaceComposerClient::getInternalDisplayId().value_or(
+ PhysicalDisplayId::fromPort(fdp->ConsumeIntegral<uint8_t>()));
mFlinger->getHwComposer().allocatePhysicalDisplay(kHwDisplayId, physicalDisplayId);
sp<IBinder> display =
@@ -570,7 +578,6 @@
mFlinger->setAutoLowLatencyMode(display, mFdp.ConsumeBool());
mFlinger->setGameContentType(display, mFdp.ConsumeBool());
mFlinger->setPowerMode(display, mFdp.ConsumeIntegral<int>());
- mFlinger->clearAnimationFrameStats();
overrideHdrTypes(display, &mFdp);
@@ -598,13 +605,14 @@
setVsyncConfig(&mFdp);
- mFlinger->flushTransactionQueues(0);
+ FTL_FAKE_GUARD(kMainThreadContext,
+ mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp)));
mFlinger->setTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
mFlinger->clearTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
mFlinger->commitOffscreenLayers();
- mFlinger->frameIsEarly(mFdp.ConsumeIntegral<nsecs_t>(), mFdp.ConsumeIntegral<int64_t>());
+ mFlinger->frameIsEarly(getFuzzedTimePoint(mFdp), getFuzzedVsyncId(mFdp));
mFlinger->computeLayerBounds();
mFlinger->startBootAnim();
@@ -615,11 +623,8 @@
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mFdp.ConsumeIntegral<uid_t>());
- mFlinger->postComposition();
+ FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postComposition());
- mFlinger->trackPresentLatency(mFdp.ConsumeIntegral<nsecs_t>(), FenceTime::NO_FENCE);
-
- FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postFrame());
mFlinger->calculateExpectedPresentTime({});
mFlinger->enableHalVirtualDisplays(mFdp.ConsumeBool());
@@ -727,7 +732,7 @@
return mFlinger->setPowerModeInternal(display, mode);
}
- auto &getTransactionQueue() { return mFlinger->mTransactionQueue; }
+ auto &getTransactionQueue() { return mFlinger->mLocklessTransactionQueue; }
auto &getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
auto setTransactionState(
@@ -742,8 +747,6 @@
listenerCallbacks, transactionId);
}
- auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(0); };
-
auto onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
return mFlinger->onTransact(code, data, reply, flags);
}
@@ -784,7 +787,8 @@
void triggerOnFrameRateOverridesChanged() override {}
surfaceflinger::test::Factory mFactory;
- sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
+ sp<SurfaceFlinger> mFlinger =
+ sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization);
scheduler::TestableScheduler *mScheduler = nullptr;
std::shared_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
};
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index 4d90b1e..aeccc52 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -77,7 +77,7 @@
void LayerFuzzer::invokeEffectLayer() {
TestableSurfaceFlinger flinger;
- sp<Client> client = sp<Client>::make(flinger.flinger());
+ sp<Client> client = sp<Client>::make(sp<SurfaceFlinger>::fromExisting(flinger.flinger()));
const LayerCreationArgs layerCreationArgs = createLayerCreationArgs(&flinger, client);
sp<EffectLayer> effectLayer = sp<EffectLayer>::make(layerCreationArgs);
@@ -109,7 +109,7 @@
void LayerFuzzer::invokeBufferStateLayer() {
TestableSurfaceFlinger flinger;
- sp<Client> client = sp<Client>::make(flinger.flinger());
+ sp<Client> client = sp<Client>::make(sp<SurfaceFlinger>::fromExisting(flinger.flinger()));
sp<BufferStateLayer> layer =
sp<BufferStateLayer>::make(createLayerCreationArgs(&flinger, client));
sp<Fence> fence = sp<Fence>::make();
@@ -125,9 +125,7 @@
ftl::yield<FenceResult>(base::unexpected(mFdp.ConsumeIntegral<status_t>())).share());
layer->releasePendingBuffer(mFdp.ConsumeIntegral<int64_t>());
- layer->finalizeFrameEventHistory(fenceTime, compositorTiming);
layer->onPostComposition(nullptr, fenceTime, fenceTime, compositorTiming);
- layer->isBufferDue(mFdp.ConsumeIntegral<int64_t>());
layer->setTransform(mFdp.ConsumeIntegral<uint32_t>());
layer->setTransformToDisplayInverse(mFdp.ConsumeBool());
@@ -151,7 +149,6 @@
layer->computeSourceBounds(getFuzzedFloatRect(&mFdp));
layer->fenceHasSignaled();
- layer->framePresentTimeIsCurrent(mFdp.ConsumeIntegral<int64_t>());
layer->onPreComposition(mFdp.ConsumeIntegral<int64_t>());
const std::vector<sp<CallbackHandle>> callbacks;
layer->setTransactionCompletedListeners(callbacks);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 1a91a69..f507ef0 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -19,6 +19,8 @@
#include <fuzzer/FuzzedDataProvider.h>
#include <processgroup/sched_policy.h>
+#include <scheduler/PresentLatencyTracker.h>
+
#include "Scheduler/DispSyncSource.h"
#include "Scheduler/OneShotTimer.h"
#include "Scheduler/VSyncDispatchTimerQueue.h"
@@ -58,6 +60,7 @@
private:
void fuzzRefreshRateSelection();
void fuzzRefreshRateConfigs();
+ void fuzzPresentLatencyTracker();
void fuzzVSyncModulator();
void fuzzVSyncPredictor();
void fuzzVSyncReactor();
@@ -93,8 +96,8 @@
thread->onHotplugReceived(getPhysicalDisplayId(), mFdp.ConsumeBool());
sp<EventThreadConnection> connection =
- new EventThreadConnection(thread.get(), mFdp.ConsumeIntegral<uint16_t>(), nullptr,
- {} /*eventRegistration*/);
+ sp<EventThreadConnection>::make(thread.get(), mFdp.ConsumeIntegral<uint16_t>(),
+ nullptr);
thread->requestNextVsync(connection);
thread->setVsyncRate(mFdp.ConsumeIntegral<uint32_t>() /*rate*/, connection);
@@ -224,8 +227,8 @@
nsecs_t time2 = time1;
uint8_t historySize = mFdp.ConsumeIntegral<uint8_t>();
- sp<FuzzImplLayer> layer1 = new FuzzImplLayer(flinger.flinger());
- sp<FuzzImplLayer> layer2 = new FuzzImplLayer(flinger.flinger());
+ sp<FuzzImplLayer> layer1 = sp<FuzzImplLayer>::make(flinger.flinger());
+ sp<FuzzImplLayer> layer2 = sp<FuzzImplLayer>::make(flinger.flinger());
for (int i = 0; i < historySize; ++i) {
historyV1.record(layer1.get(), time1, time1,
@@ -260,7 +263,7 @@
reactor.addHwVsyncTimestamp(0, std::nullopt, &periodFlushed);
reactor.addHwVsyncTimestamp(mFdp.ConsumeIntegral<nsecs_t>() /*newPeriod*/, std::nullopt,
&periodFlushed);
- sp<Fence> fence = new Fence(memfd_create("fd", MFD_ALLOW_SEALING));
+ sp<Fence> fence = sp<Fence>::make(memfd_create("fd", MFD_ALLOW_SEALING));
std::shared_ptr<FenceTime> ft = std::make_shared<FenceTime>(fence);
vSyncTracker->addVsyncTimestamp(mFdp.ConsumeIntegral<nsecs_t>());
FenceTime::Snapshot snap(mFdp.ConsumeIntegral<nsecs_t>());
@@ -319,7 +322,7 @@
LayerCreationArgs args(flinger.flinger(), client,
mFdp.ConsumeRandomLengthString(kRandomStringLength) /*name*/,
mFdp.ConsumeIntegral<uint16_t>() /*layerFlags*/, LayerMetadata());
- sp<Layer> layer = new BufferStateLayer(args);
+ sp<Layer> layer = sp<BufferStateLayer>::make(args);
layer->setFrameRateSelectionPriority(mFdp.ConsumeIntegral<int16_t>());
}
@@ -382,9 +385,16 @@
refreshRateStats.setPowerMode(mFdp.PickValueInArray(kPowerModes));
}
+void SchedulerFuzzer::fuzzPresentLatencyTracker() {
+ scheduler::PresentLatencyTracker tracker;
+ tracker.trackPendingFrame(TimePoint::fromNs(mFdp.ConsumeIntegral<nsecs_t>()),
+ FenceTime::NO_FENCE);
+}
+
void SchedulerFuzzer::process() {
fuzzRefreshRateSelection();
fuzzRefreshRateConfigs();
+ fuzzPresentLatencyTracker();
fuzzVSyncModulator();
fuzzVSyncPredictor();
fuzzVSyncReactor();
diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto
index 7def024..804a499 100644
--- a/services/surfaceflinger/layerproto/layerstrace.proto
+++ b/services/surfaceflinger/layerproto/layerstrace.proto
@@ -38,6 +38,10 @@
optional fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */
repeated LayersTraceProto entry = 2;
+
+ /* offset between real-time clock and elapsed time clock in nanoseconds.
+ Calculated as: systemTime(SYSTEM_TIME_REALTIME) - systemTime(SYSTEM_TIME_MONOTONIC) */
+ optional fixed64 real_to_elapsed_time_offset_nanos = 3;
}
/* one layers trace entry. */
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index 4f99b19..49487ee 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -36,6 +36,10 @@
fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */
repeated TransactionTraceEntry entry = 2;
+
+ /* offset between real-time clock and elapsed time clock in nanoseconds.
+ Calculated as: systemTime(SYSTEM_TIME_REALTIME) - systemTime(SYSTEM_TIME_MONOTONIC) */
+ fixed64 real_to_elapsed_time_offset_nanos = 3;
}
message TransactionTraceEntry {
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index ec18054..fedd71e 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -67,7 +67,7 @@
using android::frameworks::displayservice::V1_0::implementation::DisplayService;
using android::frameworks::displayservice::V1_0::IDisplayService;
- sp<IDisplayService> displayservice = new DisplayService();
+ sp<IDisplayService> displayservice = sp<DisplayService>::make();
status_t err = displayservice->registerAsService();
// b/141930622
@@ -153,7 +153,7 @@
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
// publish gui::ISurfaceComposer, the new AIDL interface
- sp<SurfaceComposerAIDL> composerAIDL = new SurfaceComposerAIDL(flinger);
+ sp<SurfaceComposerAIDL> composerAIDL = sp<SurfaceComposerAIDL>::make(flinger);
sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp
index 47a150d..d74bd55 100644
--- a/services/surfaceflinger/tests/BufferGenerator.cpp
+++ b/services/surfaceflinger/tests/BufferGenerator.cpp
@@ -70,12 +70,13 @@
consumer->setDefaultBufferSize(width, height);
consumer->setDefaultBufferFormat(format);
- mBufferItemConsumer = new BufferItemConsumer(consumer, GraphicBuffer::USAGE_HW_TEXTURE);
+ mBufferItemConsumer =
+ sp<BufferItemConsumer>::make(consumer, GraphicBuffer::USAGE_HW_TEXTURE);
- mListener = new BufferListener(consumer, callback);
+ mListener = sp<BufferListener>::make(consumer, callback);
mBufferItemConsumer->setFrameAvailableListener(mListener);
- mSurface = new Surface(producer, true);
+ mSurface = sp<Surface>::make(producer, true);
}
/* Used by Egl manager. The surface is never displayed. */
@@ -364,7 +365,7 @@
*outBuffer = mGraphicBuffer;
}
if (outFence) {
- *outFence = new Fence(mFence);
+ *outFence = sp<Fence>::make(mFence);
} else {
close(mFence);
}
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 8a443b8..353b813 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -77,7 +77,7 @@
sp<SurfaceControl> mVirtualSurfaceControl;
void initClient() {
- mComposerClient = new SurfaceComposerClient;
+ mComposerClient = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
}
@@ -169,7 +169,7 @@
// Anyone else can init the client.
setBinUID();
- mComposerClient = new SurfaceComposerClient;
+ mComposerClient = sp<SurfaceComposerClient>::make();
ASSERT_NO_FATAL_FAILURE(initClient());
}
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
index ce94dab..c63d251 100644
--- a/services/surfaceflinger/tests/IPC_test.cpp
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -136,7 +136,7 @@
}
status_t initClient() override {
- mClient = new SurfaceComposerClient;
+ mClient = sp<SurfaceComposerClient>::make();
auto err = mClient->initCheck();
return err;
}
@@ -221,7 +221,7 @@
ProcessState::self()->startThreadPool();
}
void SetUp() {
- mClient = new SurfaceComposerClient;
+ mClient = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, mClient->initCheck());
mPrimaryDisplay = mClient->getInternalDisplayToken();
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index 023133f..741b6f7 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -42,13 +42,13 @@
sp<SurfaceComposerClient> mScc;
sp<SurfaceControl> mNotSc;
void SetUp() override {
- mScc = new SurfaceComposerClient;
+ mScc = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, mScc->initCheck());
mNotSc = makeNotSurfaceControl();
}
sp<SurfaceControl> makeNotSurfaceControl() {
- return new SurfaceControl(mScc, new NotALayer(), 1);
+ return sp<SurfaceControl>::make(mScc, sp<NotALayer>::make(), 1);
}
};
diff --git a/services/surfaceflinger/tests/LayerBorder_test.cpp b/services/surfaceflinger/tests/LayerBorder_test.cpp
index f80c705..0d55ec1 100644
--- a/services/surfaceflinger/tests/LayerBorder_test.cpp
+++ b/services/surfaceflinger/tests/LayerBorder_test.cpp
@@ -228,10 +228,11 @@
mContainerLayer->getHandle());
sp<GraphicBuffer> buffer =
- new GraphicBuffer(400, 400, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE,
- "test");
+ sp<GraphicBuffer>::make(400u, 400u, PIXEL_FORMAT_RGBA_8888, 1u,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY |
+ BufferUsage::GPU_TEXTURE,
+ "test");
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 200, 200), Color::GREEN);
TransactionUtils::fillGraphicBufferColor(buffer, Rect(200, 200, 400, 400), Color::BLUE);
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index c8df0a0..1460fe1 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -442,8 +442,8 @@
}
TEST_F(LayerCallbackTest, Merge_DifferentClients) {
- sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
- client2(new SurfaceComposerClient);
+ sp<SurfaceComposerClient> client1(sp<SurfaceComposerClient>::make()),
+ client2(sp<SurfaceComposerClient>::make());
ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
@@ -620,8 +620,8 @@
}
TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
- sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
- client2(new SurfaceComposerClient);
+ sp<SurfaceComposerClient> client1(sp<SurfaceComposerClient>::make()),
+ client2(sp<SurfaceComposerClient>::make());
ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
@@ -669,8 +669,8 @@
}
TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) {
- sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
- client2(new SurfaceComposerClient);
+ sp<SurfaceComposerClient> client1(sp<SurfaceComposerClient>::make()),
+ client2(sp<SurfaceComposerClient>::make());
ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
@@ -730,8 +730,8 @@
}
TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) {
- sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
- client2(new SurfaceComposerClient);
+ sp<SurfaceComposerClient> client1(sp<SurfaceComposerClient>::make()),
+ client2(sp<SurfaceComposerClient>::make());
ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 0e2bc3d..bbe7ae8 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -328,7 +328,7 @@
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
ASSERT_NO_FATAL_FAILURE(
TransactionUtils::fillGraphicBufferColor(buffer, top, Color::TRANSPARENT));
@@ -352,7 +352,7 @@
shot->expectColor(bottom, Color::BLACK);
}
- buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ buffer = sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
ASSERT_NO_FATAL_FAILURE(TransactionUtils::fillGraphicBufferColor(buffer, top, Color::RED));
ASSERT_NO_FATAL_FAILURE(
@@ -894,7 +894,7 @@
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 64, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ sp<GraphicBuffer>::make(32, 64, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE);
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED);
@@ -1197,7 +1197,7 @@
size_t idx = 0;
for (auto& buffer : buffers) {
- buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ buffer = sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
Color color = colors[idx % colors.size()];
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
idx++;
@@ -1230,7 +1230,7 @@
size_t idx = 0;
for (auto& buffer : buffers) {
- buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ buffer = sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
Color color = colors[idx % colors.size()];
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
idx++;
@@ -1263,7 +1263,7 @@
size_t idx = 0;
for (auto& buffer : buffers) {
- buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ buffer = sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
Color color = colors[idx % colors.size()];
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
idx++;
@@ -1344,7 +1344,7 @@
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
sp<Fence> fence;
@@ -1370,7 +1370,7 @@
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
sp<Fence> fence = Fence::NO_FENCE;
@@ -1388,7 +1388,7 @@
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
Transaction().setBuffer(layer, buffer).setDataspace(layer, ui::Dataspace::UNKNOWN).apply();
@@ -1404,7 +1404,7 @@
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
HdrMetadata hdrMetadata;
@@ -1422,7 +1422,7 @@
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
Region region;
@@ -1440,7 +1440,7 @@
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u, kUsageFlags, "test");
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
Transaction().setBuffer(layer, buffer).setApi(layer, NATIVE_WINDOW_API_CPU).apply();
diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp
index 094b0ff..fbbf322 100644
--- a/services/surfaceflinger/tests/LayerState_test.cpp
+++ b/services/surfaceflinger/tests/LayerState_test.cpp
@@ -35,7 +35,7 @@
args.frameScaleX = 2;
args.frameScaleY = 4;
args.captureSecureLayers = true;
- args.displayToken = new BBinder();
+ args.displayToken = sp<BBinder>::make();
args.width = 10;
args.height = 20;
args.useIdentityTransform = true;
@@ -67,8 +67,8 @@
args.frameScaleX = 2;
args.frameScaleY = 4;
args.captureSecureLayers = true;
- args.layerHandle = new BBinder();
- args.excludeHandles = {new BBinder(), new BBinder()};
+ args.layerHandle = sp<BBinder>::make();
+ args.excludeHandles = {sp<BBinder>::make(), sp<BBinder>::make()};
args.childrenOnly = false;
args.grayscale = true;
@@ -92,8 +92,8 @@
TEST(LayerStateTest, ParcellingScreenCaptureResults) {
ScreenCaptureResults results;
- results.buffer = new GraphicBuffer(100, 200, PIXEL_FORMAT_RGBA_8888, 1, 0);
- results.fence = new Fence(dup(fileno(tmpfile())));
+ results.buffer = sp<GraphicBuffer>::make(100u, 200u, PIXEL_FORMAT_RGBA_8888, 1u, 0u);
+ results.fence = sp<Fence>::make(dup(fileno(tmpfile())));
results.capturedSecureLayers = true;
results.capturedDataspace = ui::Dataspace::DISPLAY_P3;
results.result = BAD_VALUE;
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index b46db65..4b91605 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -41,7 +41,7 @@
class LayerTransactionTest : public ::testing::Test {
protected:
void SetUp() override {
- mClient = new SurfaceComposerClient;
+ mClient = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
@@ -140,10 +140,13 @@
virtual void fillBufferStateLayerColor(const sp<SurfaceControl>& layer, const Color& color,
int32_t bufferWidth, int32_t bufferHeight) {
sp<GraphicBuffer> buffer =
- new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE,
- "test");
+ sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth),
+ static_cast<uint32_t>(bufferHeight), PIXEL_FORMAT_RGBA_8888,
+ 1u,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY |
+ BufferUsage::GPU_TEXTURE,
+ "test");
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight),
color);
Transaction().setBuffer(layer, buffer).apply();
@@ -209,10 +212,13 @@
const Color& topRight, const Color& bottomLeft,
const Color& bottomRight) {
sp<GraphicBuffer> buffer =
- new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE,
- "test");
+ sp<GraphicBuffer>::make(static_cast<uint32_t>(bufferWidth),
+ static_cast<uint32_t>(bufferHeight), PIXEL_FORMAT_RGBA_8888,
+ 1u,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY |
+ BufferUsage::GPU_TEXTURE,
+ "test");
ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
index ef992d6..513fdc3 100644
--- a/services/surfaceflinger/tests/LayerTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -80,7 +80,7 @@
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
const auto producer = layer->getIGraphicBufferProducer();
- const sp<IProducerListener> stubListener(new StubProducerListener);
+ const sp<IProducerListener> stubListener(sp<StubProducerListener>::make());
IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
ASSERT_EQ(OK, producer->connect(stubListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index 9cb617a..f247c9f 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -799,7 +799,7 @@
sp<Surface> surface = layer->getSurface();
sp<GraphicBuffer> buffer =
- new GraphicBuffer(width, height, PIXEL_FORMAT_RGBX_8888, 1, kUsageFlags, "test");
+ sp<GraphicBuffer>::make(width, height, PIXEL_FORMAT_RGBX_8888, 1, kUsageFlags, "test");
ASSERT_NO_FATAL_FAILURE(
TransactionUtils::fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
@@ -815,7 +815,7 @@
shot->expectColor(crop, Color::BLACK);
}
- buffer = new GraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
+ buffer = sp<GraphicBuffer>::make(width, height, PIXEL_FORMAT_RGBA_8888, 1, kUsageFlags, "test");
ASSERT_NO_FATAL_FAILURE(
TransactionUtils::fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index a6d7f58..16076ea 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -110,10 +110,10 @@
}
static sp<GraphicBuffer> getBuffer() {
- return new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
+ return sp<GraphicBuffer>::make(32u, 32u, PIXEL_FORMAT_RGBA_8888, 1u,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
}
static uint64_t generateFrameNumber() {
static uint64_t sFrameNumber = 0;
@@ -332,8 +332,10 @@
}
TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Different_Processes) {
- sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener();
- sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener();
+ sp<TransactionCompletedListener> firstCompletedListener =
+ sp<TransactionCompletedListener>::make();
+ sp<TransactionCompletedListener> secondCompletedListener =
+ sp<TransactionCompletedListener>::make();
CallbackHelper callback1, callback2;
@@ -433,8 +435,10 @@
}
TEST_F(ReleaseBufferCallbackTest, DISABLED_MergeBuffers_Different_Processes) {
- sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener();
- sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener();
+ sp<TransactionCompletedListener> firstCompletedListener =
+ sp<TransactionCompletedListener>::make();
+ sp<TransactionCompletedListener> secondCompletedListener =
+ sp<TransactionCompletedListener>::make();
TransactionCompletedListener::setInstance(firstCompletedListener);
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 6a7d8b8..d78c8a9 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -519,7 +519,7 @@
TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
LayerCaptureArgs args;
- args.layerHandle = new BBinder();
+ args.layerHandle = sp<BBinder>::make();
ScreenCaptureResults captureResults;
// Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index e9b6ba0..03201f7 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -32,7 +32,7 @@
TEST(SurfaceFlingerStress, create_and_destroy) {
auto do_stress = []() {
- sp<SurfaceComposerClient> client = new SurfaceComposerClient;
+ sp<SurfaceComposerClient> client = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, client->initCheck());
for (int j = 0; j < 1000; j++) {
auto surf = client->createSurface(String8("t"), 100, 100,
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 28e8b8c..8dcd013 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -138,7 +138,7 @@
// Allow SurfaceInterceptor write to /data
system("setenforce 0");
- mComposerClient = new SurfaceComposerClient;
+ mComposerClient = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
}
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index 8ce63bc..ad03ed3 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -53,11 +53,11 @@
consumer->setConsumerName(String8("Virtual disp consumer"));
consumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight());
- itemConsumer = new BufferItemConsumer(consumer,
- // Sample usage bits from screenrecord
- GRALLOC_USAGE_HW_VIDEO_ENCODER |
- GRALLOC_USAGE_SW_READ_OFTEN);
- sp<BufferListener> listener = new BufferListener(this);
+ itemConsumer = sp<BufferItemConsumer>::make(consumer,
+ // Sample usage bits from screenrecord
+ GRALLOC_USAGE_HW_VIDEO_ENCODER |
+ GRALLOC_USAGE_SW_READ_OFTEN);
+ sp<BufferListener> listener = sp<BufferListener>::make(this);
itemConsumer->setFrameAvailableListener(listener);
vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"),
diff --git a/services/surfaceflinger/tests/VirtualDisplay_test.cpp b/services/surfaceflinger/tests/VirtualDisplay_test.cpp
index 18e0806..f31f582 100644
--- a/services/surfaceflinger/tests/VirtualDisplay_test.cpp
+++ b/services/surfaceflinger/tests/VirtualDisplay_test.cpp
@@ -33,7 +33,7 @@
consumer->setConsumerName(String8("Virtual disp consumer"));
consumer->setDefaultBufferSize(100, 100);
- mGLConsumer = new GLConsumer(consumer, GLConsumer::TEXTURE_EXTERNAL, true, false);
+ mGLConsumer = sp<GLConsumer>::make(consumer, GLConsumer::TEXTURE_EXTERNAL, true, false);
}
sp<IGraphicBufferProducer> mProducer;
@@ -55,7 +55,7 @@
// add another sync since we are deferring the display destruction
t.apply(true);
- sp<Surface> surface = new Surface(mProducer);
+ sp<Surface> surface = sp<Surface>::make(mProducer);
sp<ANativeWindow> window(surface);
ASSERT_EQ(NO_ERROR, native_window_api_connect(window.get(), NATIVE_WINDOW_API_EGL));
diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
index bb52245..53c3c39 100644
--- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp
+++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp
@@ -29,8 +29,8 @@
protected:
void SetUp() override {
seteuid(AID_SYSTEM);
- mClient = new SurfaceComposerClient;
- mWindowInfosListener = new SyncWindowInfosListener();
+ mClient = sp<SurfaceComposerClient>::make();
+ mWindowInfosListener = sp<SyncWindowInfosListener>::make();
mClient->addWindowInfosListener(mWindowInfosListener);
}
@@ -77,7 +77,7 @@
TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) {
std::string name = "Test Layer";
- sp<IBinder> token = new BBinder();
+ sp<IBinder> token = sp<BBinder>::make();
WindowInfo windowInfo;
windowInfo.name = name;
windowInfo.token = token;
@@ -105,7 +105,7 @@
TEST_F(WindowInfosListenerTest, WindowInfoChanged) {
std::string name = "Test Layer";
- sp<IBinder> token = new BBinder();
+ sp<IBinder> token = sp<BBinder>::make();
WindowInfo windowInfo;
windowInfo.name = name;
windowInfo.token = token;
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index f824fdf..a5cca35 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -896,7 +896,7 @@
void FakeComposerClient::onSurfaceFlingerStart() {
mSurfaceComposer = nullptr;
do {
- mSurfaceComposer = new android::SurfaceComposerClient;
+ mSurfaceComposer = android::sp<android::SurfaceComposerClient>::make();
android::status_t initResult = mSurfaceComposer->initCheck();
if (initResult != android::NO_ERROR) {
ALOGD("Init result: %d", initResult);
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 00845d7..1d3401a 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -220,8 +220,8 @@
mFakeComposerClient = new FakeComposerClient();
mFakeComposerClient->setMockHal(mMockComposer.get());
- sp<V2_4::hal::ComposerClient> client = new V2_4::hal::ComposerClient(mFakeComposerClient);
- mFakeService = new FakeComposerService(client);
+ auto client = sp<V2_4::hal::ComposerClient>::make(mFakeComposerClient);
+ mFakeService = sp<FakeComposerService>::make(client);
ASSERT_EQ(android::OK, mFakeService->registerAsService("mock"));
android::hardware::ProcessState::self()->startThreadPool();
@@ -242,13 +242,13 @@
// Fake composer wants to enable VSync injection
mFakeComposerClient->onSurfaceFlingerStart();
- mComposerClient = new SurfaceComposerClient;
+ mComposerClient = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
mReceiver.reset(
new DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp,
gui::ISurfaceComposer::EventRegistration::modeChanged));
- mLooper = new Looper(false);
+ mLooper = sp<Looper>::make(false);
mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this);
}
@@ -1143,8 +1143,8 @@
// TODO: See TODO comment at DisplayTest::SetUp for background on
// the lifetime of the FakeComposerClient.
sFakeComposer = new FakeComposerClient;
- sp<V2_4::hal::ComposerClient> client = new V2_4::hal::ComposerClient(sFakeComposer);
- sp<V2_1::IComposer> fakeService = new FakeComposerService(client);
+ auto client = sp<V2_4::hal::ComposerClient>::make(sFakeComposer);
+ sp<V2_1::IComposer> fakeService = sp<FakeComposerService>::make(client);
(void)fakeService->registerAsService("mock");
android::hardware::ProcessState::self()->startThreadPool();
@@ -1167,7 +1167,7 @@
void SetUp() override {
ALOGI("TransactionTest::SetUp");
- mComposerClient = new SurfaceComposerClient;
+ mComposerClient = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
ALOGI("TransactionTest::SetUp - display");
diff --git a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
index 53de4a6..69d30c4 100644
--- a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
+++ b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp
@@ -57,8 +57,8 @@
};
void AidlPowerHalWrapperTest::SetUp() {
- mMockHal = new NiceMock<MockIPower>();
- mMockSession = new NiceMock<MockIPowerHintSession>();
+ mMockHal = sp<NiceMock<MockIPower>>::make();
+ mMockSession = sp<NiceMock<MockIPowerHintSession>>::make();
ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).WillByDefault(Return(Status::ok()));
mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal);
mWrapper->setAllowedActualDeviation(std::chrono::nanoseconds{10ms}.count());
diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp
index 6f85498..9082a22 100644
--- a/services/surfaceflinger/tests/unittests/CachingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp
@@ -26,15 +26,17 @@
class SlotGenerationTest : public testing::Test {
protected:
- sp<BufferStateLayer::HwcSlotGenerator> mHwcSlotGenerator =
- sp<BufferStateLayer::HwcSlotGenerator>::make();
- sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
- sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
- sp<GraphicBuffer> mBuffer3{new GraphicBuffer(10, 10, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+ sp<HwcSlotGenerator> mHwcSlotGenerator = sp<HwcSlotGenerator>::make();
+ sp<GraphicBuffer> mBuffer1 =
+ sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
+ sp<GraphicBuffer> mBuffer2 =
+ sp<GraphicBuffer>::make(1u, 1u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
+ sp<GraphicBuffer> mBuffer3 =
+ sp<GraphicBuffer>::make(10u, 10u, HAL_PIXEL_FORMAT_RGBA_8888, 1u, 0u);
};
TEST_F(SlotGenerationTest, getHwcCacheSlot_Invalid) {
- sp<IBinder> binder = new BBinder();
+ sp<IBinder> binder = sp<BBinder>::make();
// test getting invalid client_cache_id
client_cache_t id;
int slot = mHwcSlotGenerator->getHwcCacheSlot(id);
@@ -42,7 +44,7 @@
}
TEST_F(SlotGenerationTest, getHwcCacheSlot_Basic) {
- sp<IBinder> binder = new BBinder();
+ sp<IBinder> binder = sp<BBinder>::make();
client_cache_t id;
id.token = binder;
id.id = 0;
@@ -63,7 +65,7 @@
}
TEST_F(SlotGenerationTest, getHwcCacheSlot_Reuse) {
- sp<IBinder> binder = new BBinder();
+ sp<IBinder> binder = sp<BBinder>::make();
std::vector<client_cache_t> ids;
uint32_t cacheId = 0;
// fill up cache
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index f6ebfe5..2571e3a 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -37,7 +37,6 @@
#include <system/window.h>
#include <utils/String8.h>
-#include "ContainerLayer.h"
#include "DisplayRenderArea.h"
#include "EffectLayer.h"
#include "Layer.h"
@@ -130,13 +129,15 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
@@ -178,11 +179,11 @@
sp<DisplayDevice> mDisplay;
sp<DisplayDevice> mExternalDisplay;
sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
- new compositionengine::mock::DisplaySurface();
- mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
+ sp<compositionengine::mock::DisplaySurface>::make();
+ sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
std::vector<sp<Layer>> mAuxiliaryLayers;
- sp<GraphicBuffer> mBuffer = new GraphicBuffer();
+ sp<GraphicBuffer> mBuffer = sp<GraphicBuffer>::make();
ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
Hwc2::mock::Composer* mComposer = nullptr;
@@ -316,7 +317,7 @@
.setSecure(Derived::IS_SECURE)
.setPowerMode(Derived::INIT_POWER_MODE)
.inject();
- Mock::VerifyAndClear(test->mNativeWindow);
+ Mock::VerifyAndClear(test->mNativeWindow.get());
test->mDisplay->setLayerStack(LAYER_STACK);
}
@@ -511,7 +512,7 @@
Region(Rect(LayerProperties::HEIGHT, LayerProperties::WIDTH)));
bool ignoredRecomputeVisibleRegions;
- layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0);
+ layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
Mock::VerifyAndClear(test->mRenderEngine);
}
@@ -868,7 +869,7 @@
static FlingerLayerType createLayer(CompositionTest* test) {
FlingerLayerType layer = Base::template createLayerWithFactory<EffectLayer>(test, [test]() {
- return new EffectLayer(
+ return sp<EffectLayer>::make(
LayerCreationArgs(test->mFlinger.flinger(), sp<Client>(), "test-layer",
LayerProperties::LAYER_FLAGS, LayerMetadata()));
});
@@ -910,7 +911,7 @@
LayerCreationArgs args(test->mFlinger.flinger(), sp<Client>(), "test-layer",
LayerProperties::LAYER_FLAGS, LayerMetadata());
args.textureName = test->mFlinger.mutableTexturePool().back();
- return new BufferStateLayer(args);
+ return sp<BufferStateLayer>::make(args);
});
LayerProperties::setupLayerState(test, layer);
@@ -952,12 +953,12 @@
template <typename LayerProperties>
struct ContainerLayerVariant : public BaseLayerVariant<LayerProperties> {
using Base = BaseLayerVariant<LayerProperties>;
- using FlingerLayerType = sp<ContainerLayer>;
+ using FlingerLayerType = sp<EffectLayer>;
static FlingerLayerType createLayer(CompositionTest* test) {
LayerCreationArgs args(test->mFlinger.flinger(), sp<Client>(), "test-container-layer",
LayerProperties::LAYER_FLAGS, LayerMetadata());
- FlingerLayerType layer = new ContainerLayer(args);
+ FlingerLayerType layer = sp<EffectLayer>::make(args);
Base::template initLayerDrawingStateAndComputeBounds(test, layer);
return layer;
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index f04221c..044c112 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -66,13 +66,15 @@
void DisplayTransactionTest::injectMockScheduler() {
EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*mEventThread, createEventConnection(_, _))
- .WillOnce(Return(
- new EventThreadConnection(mEventThread, /*callingUid=*/0, ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(mEventThread,
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*mSFEventThread, createEventConnection(_, _))
- .WillOnce(Return(
- new EventThreadConnection(mSFEventThread, /*callingUid=*/0, ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(mSFEventThread,
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
mFlinger.setupScheduler(std::unique_ptr<scheduler::VsyncController>(mVsyncController),
std::unique_ptr<scheduler::VSyncTracker>(mVSyncTracker),
@@ -100,8 +102,8 @@
// This setup is only expected once per test.
ASSERT_TRUE(mConsumer == nullptr && mProducer == nullptr);
- mConsumer = new mock::GraphicBufferConsumer();
- mProducer = new mock::GraphicBufferProducer();
+ mConsumer = sp<mock::GraphicBufferConsumer>::make();
+ mProducer = sp<mock::GraphicBufferProducer>::make();
mFlinger.setCreateBufferQueueFunction([this](auto outProducer, auto outConsumer, bool) {
*outProducer = mProducer;
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index f5235ce..0c071d4 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -111,8 +111,8 @@
// Test instances
TestableSurfaceFlinger mFlinger;
- sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
- sp<GraphicBuffer> mBuffer = new GraphicBuffer();
+ sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
+ sp<GraphicBuffer> mBuffer = sp<GraphicBuffer>::make();
Hwc2::mock::PowerAdvisor mPowerAdvisor;
// These mocks are created by the test, but are destroyed by SurfaceFlinger
@@ -120,7 +120,7 @@
// to keep a reference to them for use in setting up call expectations.
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
Hwc2::mock::Composer* mComposer = nullptr;
- sp<mock::SurfaceInterceptor> mSurfaceInterceptor = new mock::SurfaceInterceptor;
+ sp<mock::SurfaceInterceptor> mSurfaceInterceptor = sp<mock::SurfaceInterceptor>::make();
mock::VsyncController* mVsyncController = new mock::VsyncController;
mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker;
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 7ee04b0..978afc5 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -193,8 +193,9 @@
ConnectionEventRecorder& recorder, EventRegistrationFlags eventRegistration,
uid_t ownerUid) {
sp<MockEventThreadConnection> connection =
- new MockEventThreadConnection(mThread.get(), ownerUid,
- mResyncCallRecorder.getInvocable(), eventRegistration);
+ sp<MockEventThreadConnection>::make(mThread.get(), ownerUid,
+ mResyncCallRecorder.getInvocable(),
+ eventRegistration);
EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
return connection;
}
diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
index 3a9b805..0b4e196 100644
--- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
@@ -95,8 +95,8 @@
sp<TestableFpsListener> mFpsListener;
fake::FakeClock* mClock = new fake::FakeClock();
- sp<FpsReporter> mFpsReporter =
- new FpsReporter(mFrameTimeline, *(mFlinger.flinger()), std::unique_ptr<Clock>(mClock));
+ sp<FpsReporter> mFpsReporter = sp<FpsReporter>::make(mFrameTimeline, *(mFlinger.flinger()),
+ std::unique_ptr<Clock>(mClock));
};
FpsReporterTest::FpsReporterTest() {
@@ -107,7 +107,7 @@
setupScheduler();
mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
- mFpsListener = new TestableFpsListener();
+ mFpsListener = sp<TestableFpsListener>::make();
}
FpsReporterTest::~FpsReporterTest() {
@@ -119,7 +119,7 @@
sp<BufferStateLayer> FpsReporterTest::createBufferStateLayer(LayerMetadata metadata = {}) {
sp<Client> client;
LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata);
- return new BufferStateLayer(args);
+ return sp<BufferStateLayer>::make(args);
}
void FpsReporterTest::setupScheduler() {
@@ -128,13 +128,15 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 756db8a..874fa7c 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -1680,7 +1680,7 @@
EXPECT_EQ(displayFrame0->getActuals().presentTime, 52);
EXPECT_EQ(displayFrame0->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
EXPECT_EQ(displayFrame0->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
- EXPECT_EQ(displayFrame0->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
+ EXPECT_EQ(displayFrame0->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed);
// case 3 - cpu time = 86 - 82 = 4, vsync period = 30
mFrameTimeline->setSfWakeUp(sfToken3, 106, Fps::fromPeriodNsecs(30));
@@ -2184,6 +2184,50 @@
EXPECT_EQ(presentedSurfaceFrame2.getJankType(), JankType::BufferStuffing);
}
+TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent_GpuAndCpuMiss) {
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
+ int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+
+ // Case 1: cpu time = 33 - 12 = 21, vsync period = 11
+ mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
+ mFrameTimeline->setSfPresent(33, presentFence1, gpuFence1);
+ auto displayFrame = getDisplayFrame(0);
+ gpuFence1->signalForTest(36);
+ presentFence1->signalForTest(52);
+
+ // Fences haven't been flushed yet, so it should be 0
+ EXPECT_EQ(displayFrame->getActuals().presentTime, 0);
+
+ addEmptyDisplayFrame();
+ displayFrame = getDisplayFrame(0);
+
+ // Fences have flushed, so the present timestamps should be updated
+ EXPECT_EQ(displayFrame->getActuals().presentTime, 52);
+ EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+ EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+ EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed);
+
+ // Case 2: No GPU fence so it will not use GPU composition.
+ mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(30));
+ mFrameTimeline->setSfPresent(66, presentFence2);
+ auto displayFrame2 = getDisplayFrame(2); // 2 because of previous empty frame
+ presentFence2->signalForTest(90);
+
+ // Fences for the frame haven't been flushed yet, so it should be 0
+ EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
+
+ addEmptyDisplayFrame();
+
+ // Fences have flushed, so the present timestamps should be updated
+ EXPECT_EQ(displayFrame2->getActuals().presentTime, 90);
+ EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+ EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+ EXPECT_EQ(displayFrame2->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
+}
+
TEST_F(FrameTimelineTest, computeFps_noLayerIds_returnsZero) {
EXPECT_EQ(mFrameTimeline->computeFps({}), 0.0f);
}
diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp
index b79909a..cd857c3 100644
--- a/services/surfaceflinger/tests/unittests/GameModeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp
@@ -57,7 +57,7 @@
sp<Client> client;
LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0,
LayerMetadata());
- return new BufferStateLayer(args);
+ return sp<BufferStateLayer>::make(args);
}
void setupScheduler() {
@@ -66,13 +66,15 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp b/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp
index 5a2c147..b7a8a93 100644
--- a/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp
@@ -29,13 +29,13 @@
sp<Client> client;
LayerCreationArgs args(flinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS,
LayerMetadata());
- return new BufferStateLayer(args);
+ return sp<BufferStateLayer>::make(args);
}
sp<Layer> EffectLayerFactory::createLayer(TestableSurfaceFlinger& flinger) {
sp<Client> client;
LayerCreationArgs args(flinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata());
- return new EffectLayer(args);
+ return sp<EffectLayer>::make(args);
}
std::string PrintToStringParamName(
@@ -53,13 +53,15 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index e0aa0b1..f20b9f9 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -32,8 +32,8 @@
using CallbackToken = scheduler::VSyncDispatch::CallbackToken;
struct NoOpCompositor final : ICompositor {
- bool commit(nsecs_t, int64_t, nsecs_t) override { return false; }
- void composite(nsecs_t, int64_t) override {}
+ bool commit(TimePoint, VsyncId, TimePoint) override { return false; }
+ void composite(TimePoint, VsyncId) override {}
void sample() override {}
} gNoOpCompositor;
@@ -41,12 +41,15 @@
struct MockHandler : MessageQueue::Handler {
using MessageQueue::Handler::Handler;
- MOCK_METHOD(void, dispatchFrame, (int64_t, nsecs_t), (override));
+ MOCK_METHOD(void, dispatchFrame, (VsyncId, TimePoint), (override));
};
explicit TestableMessageQueue(sp<MockHandler> handler)
: impl::MessageQueue(gNoOpCompositor, handler), mHandler(std::move(handler)) {}
+ // impl::MessageQueue overrides:
+ void onFrameSignal(ICompositor&, VsyncId, TimePoint) override {}
+
public:
TestableMessageQueue() : TestableMessageQueue(sp<MockHandler>::make(*this)) {}
@@ -71,7 +74,7 @@
struct MessageQueueTest : testing::Test {
void SetUp() override {
EXPECT_CALL(mVSyncDispatch, registerCallback(_, "sf")).WillOnce(Return(mCallbackToken));
- EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, mDuration));
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, kDuration));
EXPECT_CALL(mVSyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
}
@@ -80,16 +83,15 @@
TestableMessageQueue mEventQueue;
const CallbackToken mCallbackToken{5};
- constexpr static auto mDuration = std::chrono::nanoseconds(100ms);
- constexpr static auto mDifferentDuration = std::chrono::nanoseconds(250ms);
+
+ static constexpr Duration kDuration = 100ms;
+ static constexpr Duration kDifferentDuration = 250ms;
};
namespace {
-/* ------------------------------------------------------------------------
- * Test cases
- */
+
TEST_F(MessageQueueTest, commit) {
- const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
+ const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(),
.readyDuration = 0,
.earliestVsync = 0};
EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
@@ -103,7 +105,7 @@
TEST_F(MessageQueueTest, commitTwice) {
InSequence s;
- const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
+ const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(),
.readyDuration = 0,
.earliestVsync = 0};
@@ -122,7 +124,7 @@
TEST_F(MessageQueueTest, commitTwiceWithCallback) {
InSequence s;
- const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
+ const auto timing = scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(),
.readyDuration = 0,
.earliestVsync = 0};
@@ -132,33 +134,36 @@
ASSERT_TRUE(mEventQueue.getScheduledFrameTime());
EXPECT_EQ(1234, mEventQueue.getScheduledFrameTime()->time_since_epoch().count());
- const auto startTime = 100;
- const auto endTime = startTime + mDuration.count();
- const auto presentTime = 500;
- const auto vsyncId = 42;
+ constexpr TimePoint kStartTime = TimePoint::fromNs(100);
+ constexpr TimePoint kEndTime = kStartTime + kDuration;
+ constexpr TimePoint kPresentTime = TimePoint::fromNs(500);
+ constexpr VsyncId vsyncId{42};
+
EXPECT_CALL(mTokenManager,
- generateTokenForPredictions(
- frametimeline::TimelineItem(startTime, endTime, presentTime)))
- .WillOnce(Return(vsyncId));
- EXPECT_CALL(*mEventQueue.mHandler, dispatchFrame(vsyncId, presentTime)).Times(1);
- EXPECT_NO_FATAL_FAILURE(mEventQueue.vsyncCallback(presentTime, startTime, endTime));
+ generateTokenForPredictions(frametimeline::TimelineItem(kStartTime.ns(),
+ kEndTime.ns(),
+ kPresentTime.ns())))
+ .WillOnce(Return(vsyncId.value));
+ EXPECT_CALL(*mEventQueue.mHandler, dispatchFrame(vsyncId, kPresentTime)).Times(1);
+ EXPECT_NO_FATAL_FAILURE(
+ mEventQueue.vsyncCallback(kPresentTime.ns(), kStartTime.ns(), kEndTime.ns()));
EXPECT_FALSE(mEventQueue.getScheduledFrameTime());
const auto timingAfterCallback =
- scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDuration.count(),
+ scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDuration.ns(),
.readyDuration = 0,
- .earliestVsync = presentTime};
+ .earliestVsync = kPresentTime.ns()};
EXPECT_CALL(mVSyncDispatch, schedule(mCallbackToken, timingAfterCallback)).WillOnce(Return(0));
EXPECT_NO_FATAL_FAILURE(mEventQueue.scheduleFrame());
}
TEST_F(MessageQueueTest, commitWithDurationChange) {
- EXPECT_NO_FATAL_FAILURE(mEventQueue.setDuration(mDifferentDuration));
+ EXPECT_NO_FATAL_FAILURE(mEventQueue.setDuration(kDifferentDuration));
const auto timing =
- scheduler::VSyncDispatch::ScheduleTiming{.workDuration = mDifferentDuration.count(),
+ scheduler::VSyncDispatch::ScheduleTiming{.workDuration = kDifferentDuration.ns(),
.readyDuration = 0,
.earliestVsync = 0};
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index 1e6e336..6752a39 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -93,17 +93,17 @@
sp<Client> client;
LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", LAYER_FLAGS,
LayerMetadata());
- return new BufferStateLayer(args);
+ return sp<BufferStateLayer>::make(args);
}
sp<EffectLayer> RefreshRateSelectionTest::createEffectLayer() {
sp<Client> client;
LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata());
- return new EffectLayer(args);
+ return sp<EffectLayer>::make(args);
}
void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) {
- child->setParent(parent);
+ child->setParent(sp<Layer>::fromExisting(parent));
}
void RefreshRateSelectionTest::commitTransaction(Layer* layer) {
@@ -117,13 +117,15 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 93c809e..53e49eb 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -48,7 +48,8 @@
class MockEventThreadConnection : public android::EventThreadConnection {
public:
explicit MockEventThreadConnection(EventThread* eventThread)
- : EventThreadConnection(eventThread, /*callingUid=*/0, ResyncCallback()) {}
+ : EventThreadConnection(eventThread, /*callingUid*/ static_cast<uid_t>(0),
+ ResyncCallback()) {}
~MockEventThreadConnection() = default;
MOCK_METHOD1(stealReceiveChannel, binder::Status(gui::BitTube* outChannel));
@@ -79,7 +80,7 @@
mEventThread = eventThread.get();
EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0));
- mEventThreadConnection = new MockEventThreadConnection(mEventThread);
+ mEventThreadConnection = sp<MockEventThreadConnection>::make(mEventThread);
// createConnection call to scheduler makes a createEventConnection call to EventThread. Make
// sure that call gets executed and returns an EventThread::Connection object.
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index b9a5f36..6ee8174 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -78,11 +78,11 @@
}
void SetFrameRateTest::addChild(sp<Layer> layer, sp<Layer> child) {
- layer.get()->addChild(child.get());
+ layer->addChild(child);
}
void SetFrameRateTest::removeChild(sp<Layer> layer, sp<Layer> child) {
- layer.get()->removeChild(child.get());
+ layer->removeChild(child);
}
void SetFrameRateTest::commitTransaction() {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
index c7e61c9..40ef949 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
@@ -65,7 +65,7 @@
// --------------------------------------------------------------------
// Preconditions
- sp<BBinder> displayToken = new BBinder();
+ sp<BBinder> displayToken = sp<BBinder>::make();
// --------------------------------------------------------------------
// Invocation
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 5872a47..b607b88 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -87,13 +87,15 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
index 9ac2907..bc9e801 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayTransactionCommitTest.cpp
@@ -408,12 +408,12 @@
// A virtual display was added to the current state, and it has a
// surface(producer)
- sp<BBinder> displayToken = new BBinder();
+ sp<BBinder> displayToken = sp<BBinder>::make();
DisplayDeviceState state;
state.isSecure = static_cast<bool>(Case::Display::SECURE);
- sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
+ sp<mock::GraphicBufferProducer> surface{sp<mock::GraphicBufferProducer>::make()};
state.surface = surface;
mFlinger.mutableCurrentState().displays.add(displayToken, state);
@@ -479,7 +479,7 @@
// A virtual display was added to the current state, but it does not have a
// surface.
- sp<BBinder> displayToken = new BBinder();
+ sp<BBinder> displayToken = sp<BBinder>::make();
DisplayDeviceState state;
state.isSecure = static_cast<bool>(Case::Display::SECURE);
@@ -656,9 +656,11 @@
// Preconditions
// A display is set up
- auto nativeWindow = new mock::NativeWindow();
- auto displaySurface = new compositionengine::mock::DisplaySurface();
- sp<GraphicBuffer> buf = new GraphicBuffer();
+ auto nativeWindow = sp<mock::NativeWindow>::make();
+ auto displaySurface = sp<compositionengine::mock::DisplaySurface>::make();
+ sp<GraphicBuffer> buf =
+
+ sp<GraphicBuffer>::make();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
@@ -701,9 +703,9 @@
// Preconditions
// A display is set up
- auto nativeWindow = new mock::NativeWindow();
- auto displaySurface = new compositionengine::mock::DisplaySurface();
- sp<GraphicBuffer> buf = new GraphicBuffer();
+ auto nativeWindow = sp<mock::NativeWindow>::make();
+ auto displaySurface = sp<compositionengine::mock::DisplaySurface>::make();
+ sp<GraphicBuffer> buf = sp<GraphicBuffer>::make();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
@@ -750,9 +752,9 @@
// Preconditions
// A display is set up
- auto nativeWindow = new mock::NativeWindow();
- auto displaySurface = new compositionengine::mock::DisplaySurface();
- sp<GraphicBuffer> buf = new GraphicBuffer();
+ auto nativeWindow = sp<mock::NativeWindow>::make();
+ auto displaySurface = sp<compositionengine::mock::DisplaySurface>::make();
+ sp<GraphicBuffer> buf = sp<GraphicBuffer>::make();
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.setNativeWindow(nativeWindow);
display.setDisplaySurface(displaySurface);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
index 0171f1b..5951c98 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
@@ -95,7 +95,7 @@
}
TEST_F(GetDisplayNativePrimaries, notInternalDisplayToken) {
- sp<BBinder> notInternalDisplayToken = new BBinder();
+ sp<BBinder> notInternalDisplayToken = sp<BBinder>::make();
ui::DisplayPrimaries primaries;
populateDummyDisplayNativePrimaries(primaries);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
index 3d576f4..98249bf 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
@@ -78,11 +78,6 @@
auto displayDevice = primaryDisplay.mutableDisplayDevice();
EXPECT_EQ(PowerMode::ON, displayDevice->getPowerMode());
- // The display refresh period should be set in the orientedDisplaySpaceRect tracker.
- FrameStats stats;
- mFlinger.getAnimFrameTracker().getStats(&stats);
- EXPECT_EQ(DEFAULT_VSYNC_PERIOD, stats.refreshPeriodNano);
-
// The display transaction needed flag should be set.
EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
}
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
index c2d87f2..e256d2c 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -60,8 +60,8 @@
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
sp<DisplayDevice> mDisplay;
sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
- new compositionengine::mock::DisplaySurface();
- mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
+ sp<compositionengine::mock::DisplaySurface>::make();
+ sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
mock::TimeStats* mTimeStats = new mock::TimeStats();
Hwc2::mock::PowerAdvisor* mPowerAdvisor = nullptr;
Hwc2::mock::Composer* mComposer = nullptr;
@@ -97,6 +97,7 @@
.setNativeWindow(mNativeWindow)
.setPowerMode(hal::PowerMode::ON)
.inject();
+ mFlinger.mutableActiveDisplayToken() = mDisplay->getDisplayToken();
}
void SurfaceFlingerPowerHintTest::setupScheduler() {
@@ -105,13 +106,15 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
@@ -130,22 +133,41 @@
TEST_F(SurfaceFlingerPowerHintTest, sendDurationsIncludingHwcWaitTime) {
ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true));
- const std::chrono::nanoseconds mockVsyncPeriod = 15ms;
EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(_)).Times(1);
-
- const nsecs_t now = systemTime();
- const std::chrono::nanoseconds mockHwcRunTime = 20ms;
EXPECT_CALL(*mDisplaySurface,
prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc))
.Times(1);
- EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _))
- .WillOnce([mockHwcRunTime] {
- std::this_thread::sleep_for(mockHwcRunTime);
- return hardware::graphics::composer::V2_1::Error::NONE;
- });
+ EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _)).WillOnce([] {
+ constexpr Duration kMockHwcRunTime = 20ms;
+ std::this_thread::sleep_for(kMockHwcRunTime);
+ return hardware::graphics::composer::V2_1::Error::NONE;
+ });
EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(1);
- static constexpr bool kVsyncId = 123; // arbitrary
- mFlinger.commitAndComposite(now, kVsyncId, now + mockVsyncPeriod.count());
+
+ const TimePoint frameTime = scheduler::SchedulerClock::now();
+ constexpr Period kMockVsyncPeriod = 15ms;
+ mFlinger.commitAndComposite(frameTime, VsyncId{123}, frameTime + kMockVsyncPeriod);
+}
+
+TEST_F(SurfaceFlingerPowerHintTest, inactiveOnDisplayDoze) {
+ ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true));
+
+ mDisplay->setPowerMode(hal::PowerMode::DOZE);
+
+ EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(_)).Times(0);
+ EXPECT_CALL(*mDisplaySurface,
+ prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc))
+ .Times(1);
+ EXPECT_CALL(*mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _, _)).WillOnce([] {
+ constexpr Duration kMockHwcRunTime = 20ms;
+ std::this_thread::sleep_for(kMockHwcRunTime);
+ return hardware::graphics::composer::V2_1::Error::NONE;
+ });
+ EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(0);
+
+ const TimePoint frameTime = scheduler::SchedulerClock::now();
+ constexpr Period kMockVsyncPeriod = 15ms;
+ mFlinger.commitAndComposite(frameTime, VsyncId{123}, frameTime + kMockVsyncPeriod);
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
index 7d9e22b..9c7f55b 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
@@ -34,7 +34,7 @@
// Preconditions
// We have an unknown display token not associated with a known display
- sp<BBinder> displayToken = new BBinder();
+ sp<BBinder> displayToken = sp<BBinder>::make();
// The requested display state references the unknown display.
DisplayState state;
@@ -95,7 +95,7 @@
display.inject();
// There is a surface that can be set.
- sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
+ sp<mock::GraphicBufferProducer> surface = sp<mock::GraphicBufferProducer>::make();
// The current display state has the surface set
display.mutableCurrentDisplayState().surface = surface;
@@ -132,7 +132,7 @@
display.inject();
// There is a surface that can be set.
- sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
+ sp<mock::GraphicBufferProducer> surface = sp<mock::GraphicBufferProducer>::make();
// The current display state does not have a surface
display.mutableCurrentDisplayState().surface = nullptr;
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 583cf5f..1756368 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -140,7 +140,6 @@
static void verifyPostconditions(DisplayTransactionTest* test) {
EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
- EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
}
};
@@ -155,7 +154,6 @@
static void verifyPostconditions(DisplayTransactionTest* test) {
EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
- EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
}
};
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index a0e078b..6aeb3fe 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -197,10 +197,10 @@
template <typename Case>
void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() {
- const sp<BBinder> displayToken = new BBinder();
+ const sp<BBinder> displayToken = sp<BBinder>::make();
const sp<compositionengine::mock::DisplaySurface> displaySurface =
- new compositionengine::mock::DisplaySurface();
- const sp<mock::GraphicBufferProducer> producer = new mock::GraphicBufferProducer();
+ sp<compositionengine::mock::DisplaySurface>::make();
+ const auto producer = sp<mock::GraphicBufferProducer>::make();
// --------------------------------------------------------------------
// Preconditions
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 4708572..66cdfd7 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -109,8 +109,8 @@
private:
// ICompositor overrides:
- bool commit(nsecs_t, int64_t, nsecs_t) override { return false; }
- void composite(nsecs_t, int64_t) override {}
+ bool commit(TimePoint, VsyncId, TimePoint) override { return false; }
+ void composite(TimePoint, VsyncId) override {}
void sample() override {}
};
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 60285f9..8f87123 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -27,10 +27,10 @@
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/mock/DisplaySurface.h>
+#include <ftl/fake_guard.h>
#include <gui/ScreenCaptureResults.h>
#include "BufferStateLayer.h"
-#include "ContainerLayer.h"
#include "DisplayDevice.h"
#include "EffectLayer.h"
#include "FakeVsyncConfiguration.h"
@@ -84,21 +84,21 @@
}
sp<SurfaceInterceptor> createSurfaceInterceptor() override {
- return new android::impl::SurfaceInterceptor();
+ return sp<android::impl::SurfaceInterceptor>::make();
}
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
- return new StartPropertySetThread(timestampPropertyValue);
+ return sp<StartPropertySetThread>::make(timestampPropertyValue);
}
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) override {
- return new DisplayDevice(creationArgs);
+ return sp<DisplayDevice>::make(creationArgs);
}
sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
std::string requestorName) override {
- return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
+ return sp<GraphicBuffer>::make(width, height, format, layerCount, usage, requestorName);
}
void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
@@ -127,10 +127,6 @@
sp<EffectLayer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; }
- sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override {
- return nullptr;
- }
-
std::unique_ptr<FrameTracer> createFrameTracer() override {
return std::make_unique<mock::FrameTracer>();
}
@@ -321,25 +317,22 @@
* Forwarding for functions being tested
*/
- nsecs_t commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVSyncTime) {
+ TimePoint commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVSyncTime) {
mFlinger->commit(frameTime, vsyncId, expectedVSyncTime);
return frameTime;
}
- nsecs_t commit(nsecs_t frameTime, int64_t vsyncId) {
- std::chrono::nanoseconds period = 10ms;
- return commit(frameTime, vsyncId, frameTime + period.count());
+ TimePoint commit(TimePoint frameTime, VsyncId vsyncId) {
+ return commit(frameTime, vsyncId, frameTime + Period(10ms));
}
- nsecs_t commit() {
- const nsecs_t now = systemTime();
- const nsecs_t expectedVsyncTime = now + 10'000'000;
- return commit(now, kVsyncId, expectedVsyncTime);
+ TimePoint commit() {
+ const TimePoint frameTime = scheduler::SchedulerClock::now();
+ return commit(frameTime, kVsyncId);
}
- void commitAndComposite(const nsecs_t frameTime, const int64_t vsyncId,
- const nsecs_t expectedVsyncTime) {
- mFlinger->composite(commit(frameTime, vsyncId, expectedVsyncTime), kVsyncId);
+ void commitAndComposite(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime) {
+ mFlinger->composite(commit(frameTime, vsyncId, expectedVsyncTime), vsyncId);
}
void commitAndComposite() { mFlinger->composite(commit(), kVsyncId); }
@@ -421,7 +414,7 @@
return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
}
- auto& getTransactionQueue() { return mFlinger->mTransactionQueue; }
+ auto& getTransactionQueue() { return mFlinger->mLocklessTransactionQueue; }
auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
auto& getTransactionCommittedSignals() { return mFlinger->mTransactionCommittedSignals; }
@@ -437,7 +430,9 @@
listenerCallbacks, transactionId);
}
- auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(0); };
+ auto flushTransactionQueues() {
+ return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues(kVsyncId));
+ }
auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
return mFlinger->onTransact(code, data, reply, flags);
@@ -481,8 +476,6 @@
* Read-only access to private data to assert post-conditions.
*/
- const auto& getAnimFrameTracker() const { return mFlinger->mAnimFrameTracker; }
- const auto& getHasPoweredOff() const { return mFlinger->mHasPoweredOff; }
const auto& getVisibleRegionsDirty() const { return mFlinger->mVisibleRegionsDirty; }
auto& getHwComposer() const {
return static_cast<impl::HWComposer&>(mFlinger->getHwComposer());
@@ -721,8 +714,8 @@
std::optional<ui::DisplayConnectionType> connectionType,
std::optional<hal::HWDisplayId> hwcDisplayId, bool isPrimary)
: mFlinger(flinger),
- mCreationArgs(flinger.mFlinger.get(), flinger.mFlinger->getHwComposer(),
- mDisplayToken, display),
+ mCreationArgs(flinger.mFlinger, flinger.mFlinger->getHwComposer(), mDisplayToken,
+ display),
mHwcDisplayId(hwcDisplayId) {
mCreationArgs.connectionType = connectionType;
mCreationArgs.isPrimary = isPrimary;
@@ -870,13 +863,13 @@
private:
TestableSurfaceFlinger& mFlinger;
- sp<BBinder> mDisplayToken = new BBinder();
+ sp<BBinder> mDisplayToken = sp<BBinder>::make();
DisplayDeviceCreationArgs mCreationArgs;
const std::optional<hal::HWDisplayId> mHwcDisplayId;
};
private:
- constexpr static int64_t kVsyncId = 123;
+ static constexpr VsyncId kVsyncId{123};
surfaceflinger::test::Factory mFactory;
sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 84f1170..efb9e0c 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -60,13 +60,15 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
EXPECT_CALL(*mVSyncTracker, currentPeriod())
@@ -117,7 +119,7 @@
}
void NotPlacedOnTransactionQueue(uint32_t flags) {
- ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+ ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
TransactionInfo transaction;
setupSingle(transaction, flags,
@@ -140,12 +142,12 @@
EXPECT_LE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout());
}
// Each transaction should have been placed on the transaction queue
- auto transactionQueue = mFlinger.getTransactionQueue();
- EXPECT_EQ(1u, transactionQueue.size());
+ auto& transactionQueue = mFlinger.getTransactionQueue();
+ EXPECT_FALSE(transactionQueue.isEmpty());
}
void PlaceOnTransactionQueue(uint32_t flags) {
- ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+ ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
// first check will see desired present time has not passed,
@@ -171,12 +173,12 @@
applicationSentTime + mFlinger.getAnimationTransactionTimeout());
}
// This transaction should have been placed on the transaction queue
- auto transactionQueue = mFlinger.getTransactionQueue();
- EXPECT_EQ(1u, transactionQueue.size());
+ auto& transactionQueue = mFlinger.getTransactionQueue();
+ EXPECT_FALSE(transactionQueue.isEmpty());
}
void BlockedByPriorTransaction(uint32_t flags) {
- ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+ ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
nsecs_t time = systemTime();
EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(2);
@@ -239,8 +241,8 @@
int mTransactionNumber = 0;
};
-TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
- ASSERT_EQ(0u, mFlinger.getTransactionQueue().size());
+TEST_F(TransactionApplicationTest, AddToPendingQueue) {
+ ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
TransactionInfo transactionA; // transaction to go on pending queue
@@ -253,10 +255,27 @@
mHasListenerCallbacks, mCallbacks, transactionA.id);
auto& transactionQueue = mFlinger.getTransactionQueue();
- ASSERT_EQ(1u, transactionQueue.size());
+ ASSERT_FALSE(transactionQueue.isEmpty());
- auto& transactionState = transactionQueue.front();
+ auto transactionState = transactionQueue.pop().value();
checkEqual(transactionA, transactionState);
+}
+
+TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
+ ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
+ EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1);
+
+ TransactionInfo transactionA; // transaction to go on pending queue
+ setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ s2ns(1), false,
+ FrameTimelineInfo{});
+ mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
+ transactionA.displays, transactionA.flags, transactionA.applyToken,
+ transactionA.inputWindowCommands, transactionA.desiredPresentTime,
+ transactionA.isAutoTimestamp, transactionA.uncacheBuffer,
+ mHasListenerCallbacks, mCallbacks, transactionA.id);
+
+ auto& transactionQueue = mFlinger.getTransactionQueue();
+ ASSERT_FALSE(transactionQueue.isEmpty());
// because flushing uses the cached expected present time, we send an empty
// transaction here (sending a null applyToken to fake it as from a
@@ -272,7 +291,7 @@
// passed
mFlinger.flushTransactionQueues();
- EXPECT_EQ(0u, transactionQueue.size());
+ EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
}
TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) {
@@ -306,7 +325,9 @@
void TearDown() override {
// Clear all transaction queues to release all transactions we sent
// in the tests. Otherwise, gmock complains about memory leaks.
- mFlinger.getTransactionQueue().clear();
+ while (!mFlinger.getTransactionQueue().isEmpty()) {
+ mFlinger.getTransactionQueue().pop();
+ }
mFlinger.getPendingTransactionQueue().clear();
mFlinger.getTransactionCommittedSignals().clear();
mFlinger.commitTransactionsLocked(eTransactionMask);
@@ -358,7 +379,7 @@
void setTransactionStates(const std::vector<TransactionInfo>& transactions,
size_t expectedTransactionsApplied,
size_t expectedTransactionsPending) {
- EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+ EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
for (const auto& transaction : transactions) {
@@ -370,7 +391,7 @@
mHasListenerCallbacks, mCallbacks, transaction.id);
}
mFlinger.flushTransactionQueues();
- EXPECT_EQ(0u, mFlinger.getTransactionQueue().size());
+ EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty());
EXPECT_EQ(expectedTransactionsPending, mFlinger.getPendingTransactionQueue().size());
EXPECT_EQ(expectedTransactionsApplied, mFlinger.getTransactionCommittedSignals().size());
}
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index 5364630..cd64325 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -60,7 +60,7 @@
sp<Client> client;
LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0,
LayerMetadata());
- return new BufferStateLayer(args);
+ return sp<BufferStateLayer>::make(args);
}
void commitTransaction(Layer* layer) {
@@ -74,13 +74,15 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
@@ -101,7 +103,7 @@
void BLASTTransactionSendsFrameTracerEvents() {
sp<BufferStateLayer> layer = createBufferStateLayer();
- sp<Fence> fence(new Fence());
+ sp<Fence> fence(sp<Fence>::make());
int32_t layerId = layer->getSequence();
uint64_t bufferId = 42;
uint64_t frameNumber = 5;
@@ -127,7 +129,6 @@
dequeueTime, FrameTimelineInfo{});
commitTransaction(layer.get());
- bool computeVisisbleRegions;
nsecs_t latchTime = 25;
EXPECT_CALL(*mFlinger.getFrameTracer(),
traceFence(layerId, bufferId, frameNumber, _,
@@ -135,7 +136,7 @@
EXPECT_CALL(*mFlinger.getFrameTracer(),
traceTimestamp(layerId, bufferId, frameNumber, latchTime,
FrameTracer::FrameEvent::LATCH, /*duration*/ 0));
- layer->updateTexImage(computeVisisbleRegions, latchTime, /*expectedPresentTime*/ 0);
+ layer->updateTexImage(latchTime);
auto glDoneFence = fenceFactory.createFenceTimeForTest(fence);
auto presentFence = fenceFactory.createFenceTimeForTest(fence);
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index 669fa3a..1f011be 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -27,8 +27,8 @@
namespace android {
TEST(TransactionProtoParserTest, parse) {
- const sp<IBinder> layerHandle = new BBinder();
- const sp<IBinder> displayHandle = new BBinder();
+ const sp<IBinder> layerHandle = sp<BBinder>::make();
+ const sp<IBinder> displayHandle = sp<BBinder>::make();
TransactionState t1;
t1.originPid = 1;
t1.originUid = 2;
@@ -49,7 +49,7 @@
ComposerState s;
if (i == 1) {
layer.parentSurfaceControlForChild =
- new SurfaceControl(SurfaceComposerClient::getDefault(), layerHandle, 42);
+ sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), layerHandle, 42);
}
s.state = layer;
t1.states.add(s);
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index 6d58303..d5823c3 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -60,7 +60,7 @@
sp<Client> client;
LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 0,
LayerMetadata());
- return new BufferStateLayer(args);
+ return sp<BufferStateLayer>::make(args);
}
void commitTransaction(Layer* layer) {
@@ -74,13 +74,15 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
@@ -115,7 +117,7 @@
void PresentedSurfaceFrameForBufferTransaction() {
sp<BufferStateLayer> layer = createBufferStateLayer();
- sp<Fence> fence(new Fence());
+ sp<Fence> fence(sp<Fence>::make());
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
BufferData bufferData;
bufferData.acquireFence = fence;
@@ -140,8 +142,7 @@
// Buffers are presented only at latch time.
EXPECT_EQ(PresentState::Unknown, surfaceFrame->getPresentState());
- bool computeVisisbleRegions;
- layer->updateTexImage(computeVisisbleRegions, 15, 0);
+ layer->updateTexImage(15);
EXPECT_EQ(1, surfaceFrame->getToken());
EXPECT_EQ(true, surfaceFrame->getIsBuffer());
@@ -151,7 +152,7 @@
void DroppedSurfaceFrameForBufferTransaction() {
sp<BufferStateLayer> layer = createBufferStateLayer();
- sp<Fence> fence1(new Fence());
+ sp<Fence> fence1(sp<Fence>::make());
auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
BufferData bufferData;
bufferData.acquireFence = fence1;
@@ -171,7 +172,7 @@
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
- sp<Fence> fence2(new Fence());
+ sp<Fence> fence2(sp<Fence>::make());
auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
nsecs_t start = systemTime();
bufferData.acquireFence = fence2;
@@ -192,8 +193,7 @@
const auto presentedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
commitTransaction(layer.get());
- bool computeVisisbleRegions;
- layer->updateTexImage(computeVisisbleRegions, 15, 0);
+ layer->updateTexImage(15);
EXPECT_EQ(1, droppedSurfaceFrame->getToken());
EXPECT_EQ(true, droppedSurfaceFrame->getIsBuffer());
@@ -218,7 +218,7 @@
EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
- sp<Fence> fence(new Fence());
+ sp<Fence> fence(sp<Fence>::make());
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
BufferData bufferData;
bufferData.acquireFence = fence;
@@ -243,15 +243,14 @@
// Buffers are presented only at latch time.
EXPECT_EQ(PresentState::Unknown, surfaceFrame->getPresentState());
- bool computeVisisbleRegions;
- layer->updateTexImage(computeVisisbleRegions, 15, 0);
+ layer->updateTexImage(15);
EXPECT_EQ(PresentState::Presented, surfaceFrame->getPresentState());
}
void BufferlessSurfaceFrameNotCreatedIfBufferSufaceFrameExists() {
sp<BufferStateLayer> layer = createBufferStateLayer();
- sp<Fence> fence(new Fence());
+ sp<Fence> fence(sp<Fence>::make());
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
BufferData bufferData;
bufferData.acquireFence = fence;
@@ -294,7 +293,7 @@
ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto bufferlessSurfaceFrame2 = layer->mDrawingState.bufferlessSurfaceFramesTX[4];
- sp<Fence> fence(new Fence());
+ sp<Fence> fence(sp<Fence>::make());
auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
BufferData bufferData;
bufferData.acquireFence = fence;
@@ -331,8 +330,7 @@
// Buffers are presented only at latch time.
EXPECT_EQ(PresentState::Unknown, bufferSurfaceFrameTX->getPresentState());
- bool computeVisisbleRegions;
- layer->updateTexImage(computeVisisbleRegions, 15, 0);
+ layer->updateTexImage(15);
EXPECT_EQ(PresentState::Presented, bufferSurfaceFrameTX->getPresentState());
}
@@ -340,7 +338,7 @@
void PendingSurfaceFramesRemovedAfterClassification() {
sp<BufferStateLayer> layer = createBufferStateLayer();
- sp<Fence> fence1(new Fence());
+ sp<Fence> fence1(sp<Fence>::make());
auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
BufferData bufferData;
bufferData.acquireFence = fence1;
@@ -359,7 +357,7 @@
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
- sp<Fence> fence2(new Fence());
+ sp<Fence> fence2(sp<Fence>::make());
auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
bufferData.acquireFence = fence2;
bufferData.frameNumber = 1;
@@ -377,8 +375,7 @@
auto presentedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
commitTransaction(layer.get());
- bool computeVisisbleRegions;
- layer->updateTexImage(computeVisisbleRegions, 15, 0);
+ layer->updateTexImage(15);
// Both the droppedSurfaceFrame and presentedSurfaceFrame should be in
// pendingJankClassifications.
@@ -393,7 +390,7 @@
void BufferSurfaceFrame_ReplaceValidTokenBufferWithInvalidTokenBuffer() {
sp<BufferStateLayer> layer = createBufferStateLayer();
- sp<Fence> fence1(new Fence());
+ sp<Fence> fence1(sp<Fence>::make());
auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
BufferData bufferData;
bufferData.acquireFence = fence1;
@@ -413,7 +410,7 @@
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame1 = layer->mDrawingState.bufferSurfaceFrameTX;
- sp<Fence> fence2(new Fence());
+ sp<Fence> fence2(sp<Fence>::make());
auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
auto dropStartTime1 = systemTime();
bufferData.acquireFence = fence2;
@@ -434,7 +431,7 @@
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame2 = layer->mDrawingState.bufferSurfaceFrameTX;
- sp<Fence> fence3(new Fence());
+ sp<Fence> fence3(sp<Fence>::make());
auto acquireFence3 = fenceFactory.createFenceTimeForTest(fence3);
auto dropStartTime2 = systemTime();
bufferData.acquireFence = fence3;
@@ -458,8 +455,7 @@
const auto presentedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
commitTransaction(layer.get());
- bool computeVisisbleRegions;
- layer->updateTexImage(computeVisisbleRegions, 15, 0);
+ layer->updateTexImage(15);
EXPECT_EQ(1, droppedSurfaceFrame1->getToken());
EXPECT_EQ(true, droppedSurfaceFrame1->getIsBuffer());
@@ -485,7 +481,7 @@
uint32_t surfaceFramesPendingClassification = 0;
std::vector<std::shared_ptr<frametimeline::SurfaceFrame>> bufferlessSurfaceFrames;
for (int i = 0; i < 10; i += 2) {
- sp<Fence> fence(new Fence());
+ sp<Fence> fence(sp<Fence>::make());
BufferData bufferData;
bufferData.acquireFence = fence;
bufferData.frameNumber = 1;
@@ -517,8 +513,7 @@
}
auto presentedBufferSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
- bool computeVisisbleRegions;
- layer->updateTexImage(computeVisisbleRegions, 15, 0);
+ layer->updateTexImage(15);
// BufferlessSurfaceFrames are immediately set to presented and added to the DisplayFrame.
// Since we don't have access to DisplayFrame here, trigger an onPresent directly.
for (auto& surfaceFrame : bufferlessSurfaceFrames) {
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 8ec918d..2dbcfbd 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -101,10 +101,10 @@
void SetUp() override {
// add layers
mTracing.setBufferSize(SMALL_BUFFER_SIZE);
- const sp<IBinder> fakeLayerHandle = new BBinder();
+ const sp<IBinder> fakeLayerHandle = sp<BBinder>::make();
mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mParentLayerId, "parent",
123 /* flags */, -1 /* parentId */);
- const sp<IBinder> fakeChildLayerHandle = new BBinder();
+ const sp<IBinder> fakeChildLayerHandle = sp<BBinder>::make();
mTracing.onLayerAdded(fakeChildLayerHandle->localBinder(), mChildLayerId, "child",
456 /* flags */, mParentLayerId);
@@ -234,10 +234,10 @@
void SetUp() override {
// add layers
mTracing.setBufferSize(SMALL_BUFFER_SIZE);
- const sp<IBinder> fakeLayerHandle = new BBinder();
+ const sp<IBinder> fakeLayerHandle = sp<BBinder>::make();
mTracing.onLayerAdded(fakeLayerHandle->localBinder(), mLayerId, "Test Layer",
123 /* flags */, -1 /* parentId */);
- const sp<IBinder> fakeMirrorLayerHandle = new BBinder();
+ const sp<IBinder> fakeMirrorLayerHandle = sp<BBinder>::make();
mTracing.onMirrorLayerAdded(fakeMirrorLayerHandle->localBinder(), mMirrorLayerId, "Mirror",
mLayerId);
mTracing.onLayerAddedToDrawingState(mLayerId, mVsyncId);
diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
index 15fea9c..45ebb85 100644
--- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp
@@ -99,7 +99,7 @@
LayerMetadata metadata = {}) {
sp<Client> client;
LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, metadata);
- return new BufferStateLayer(args);
+ return sp<BufferStateLayer>::make(args);
}
void TunnelModeEnabledReporterTest::setupScheduler() {
@@ -108,13 +108,15 @@
EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*eventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
- .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
- ResyncCallback())));
+ .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+ mock::EventThread::kCallingUid,
+ ResyncCallback())));
auto vsyncController = std::make_unique<mock::VsyncController>();
auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index b7f968d..f660753 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -44,6 +44,8 @@
ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_))
.WillByDefault(Invoke(this, &MockVSyncTracker::nextVSyncTime));
ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true));
+ ON_CALL(*this, currentPeriod())
+ .WillByDefault(Invoke(this, &MockVSyncTracker::getCurrentPeriod));
}
MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t));
@@ -62,6 +64,8 @@
return (timePoint - (timePoint % mPeriod) + mPeriod);
}
+ nsecs_t getCurrentPeriod() const { return mPeriod; }
+
protected:
nsecs_t const mPeriod;
};
@@ -393,6 +397,43 @@
EXPECT_THAT(cb1.mCalls[0], Eq(1063));
}
+TEST_F(VSyncDispatchTimerQueueTest, noCloseCallbacksAfterPeriodChange) {
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
+ .Times(4)
+ .WillOnce(Return(1000))
+ .WillOnce(Return(2000))
+ .WillOnce(Return(2500))
+ .WillOnce(Return(4000));
+
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 3900)).InSequence(seq);
+
+ CountingCallback cb(mDispatch);
+
+ mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 0});
+
+ advanceToNextCallback();
+
+ ASSERT_THAT(cb.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb.mCalls[0], Eq(1000));
+
+ mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
+
+ advanceToNextCallback();
+
+ ASSERT_THAT(cb.mCalls.size(), Eq(2));
+ EXPECT_THAT(cb.mCalls[1], Eq(2000));
+
+ mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000});
+
+ advanceToNextCallback();
+
+ ASSERT_THAT(cb.mCalls.size(), Eq(3));
+ EXPECT_THAT(cb.mCalls[2], Eq(4000));
+}
+
TEST_F(VSyncDispatchTimerQueueTest, rearmsFaroutTimeoutWhenCancellingCloseOne) {
EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
.Times(4)
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 30a3f9a..a35ff96 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -77,12 +77,12 @@
};
std::shared_ptr<android::FenceTime> generateInvalidFence() {
- sp<Fence> fence = new Fence();
+ sp<Fence> fence = sp<Fence>::make();
return std::make_shared<android::FenceTime>(fence);
}
std::shared_ptr<android::FenceTime> generatePendingFence() {
- sp<Fence> fence = new Fence(dup(fileno(tmpfile())));
+ sp<Fence> fence = sp<Fence>::make(dup(fileno(tmpfile())));
return std::make_shared<android::FenceTime>(fence);
}
@@ -92,7 +92,7 @@
}
std::shared_ptr<android::FenceTime> generateSignalledFenceWithTime(nsecs_t time) {
- sp<Fence> fence = new Fence(dup(fileno(tmpfile())));
+ sp<Fence> fence = sp<Fence>::make(dup(fileno(tmpfile())));
std::shared_ptr<android::FenceTime> ft = std::make_shared<android::FenceTime>(fence);
signalFenceWithTime(ft, time);
return ft;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index d6dca45..aede250 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -53,7 +53,8 @@
MOCK_METHOD(void, setRequiresClientComposition,
(DisplayId displayId, bool requiresClientComposition), (override));
MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override));
- MOCK_METHOD(void, setPresentFenceTime, (nsecs_t presentFenceTime), (override));
+ MOCK_METHOD(void, setSfPresentTiming, (nsecs_t presentFenceTime, nsecs_t presentEndTime),
+ (override));
MOCK_METHOD(void, setHwcPresentDelayedTime,
(DisplayId displayId,
std::chrono::steady_clock::time_point earliestFrameStartTime));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index d30dc42..ded6806 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -24,6 +24,8 @@
class EventThread : public android::EventThread {
public:
+ static constexpr auto kCallingUid = static_cast<uid_t>(0);
+
EventThread();
~EventThread() override;
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
index 6ada549..cb7040a 100644
--- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -39,7 +39,7 @@
SurfaceComposerClient::Transaction().apply(true);
captureArgs.dataspace = ui::Dataspace::V0_SRGB;
- const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+ const sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make();
binder::Status status = sf->captureDisplay(captureArgs, captureListener);
status_t err = statusTFromBinderStatus(status);
if (err != NO_ERROR) {
@@ -73,7 +73,7 @@
SurfaceComposerClient::Transaction().apply(true);
captureArgs.dataspace = ui::Dataspace::V0_SRGB;
- const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
+ const sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make();
binder::Status status = sf->captureLayers(captureArgs, captureListener);
status_t err = statusTFromBinderStatus(status);
if (err != NO_ERROR) {
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index 667dfb9..8b4a6be 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -18,7 +18,13 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+// This file is included by modules that have host support but android/looper.h is not supported
+// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled.
+#ifndef __BIONIC__
+#define __REMOVED_IN(x) __attribute__((deprecated))
+#endif
#include <android/looper.h>
+
#include <gui/DisplayEventReceiver.h>
#include <utils/Looper.h>
@@ -55,8 +61,7 @@
{
DisplayEventReceiver myDisplayEvent;
-
- sp<Looper> loop = new Looper(false);
+ sp<Looper> loop = sp<Looper>::make(false);
loop->addFd(myDisplayEvent.getFd(), 0, ALOOPER_EVENT_INPUT, receiver,
&myDisplayEvent);
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 3818b25..0a33760 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1234,11 +1234,15 @@
decodePixelFormat(native_pixel_format).c_str(), strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
- err = native_window_set_buffers_data_space(window, native_dataspace);
- if (err != android::OK) {
- ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
- native_dataspace, strerror(-err), err);
- return VK_ERROR_SURFACE_LOST_KHR;
+
+ /* Respect consumer default dataspace upon HAL_DATASPACE_ARBITRARY. */
+ if (native_dataspace != HAL_DATASPACE_ARBITRARY) {
+ err = native_window_set_buffers_data_space(window, native_dataspace);
+ if (err != android::OK) {
+ ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
+ native_dataspace, strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
}
err = native_window_set_buffers_dimensions(