diff options
103 files changed, 1503 insertions, 744 deletions
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 4f80190954..17e5cc119d 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1089,8 +1089,14 @@ static void MaybeAddSystemTraceToZip() { // This function copies into the .zip the system trace that was snapshotted // by the early call to MaybeSnapshotSystemTrace(), if any background // tracing was happening. - if (!ds.has_system_trace_) { - // No background trace was happening at the time dumpstate was invoked. + bool system_trace_exists = access(SYSTEM_TRACE_SNAPSHOT, F_OK) == 0; + if (!system_trace_exists) { + // No background trace was happening at the time MaybeSnapshotSystemTrace() was invoked. + if (!PropertiesHelper::IsUserBuild()) { + MYLOGI( + "No system traces found. Check for previously uploaded traces by looking for " + "go/trace-uuid in logcat") + } return; } ds.AddZipEntry( @@ -1650,8 +1656,6 @@ Dumpstate::RunStatus Dumpstate::dumpstate() { dump_board = ds.dump_pool_->enqueueTaskWithFd( DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1); dump_checkins = ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1); - post_process_ui_traces = ds.dump_pool_->enqueueTask( - POST_PROCESS_UI_TRACES_TASK, &Dumpstate::MaybePostProcessUiTraces, &ds); } // Dump various things. Note that anything that takes "long" (i.e. several seconds) should @@ -1861,12 +1865,6 @@ Dumpstate::RunStatus Dumpstate::dumpstate() { DumpIncidentReport); } - if (ds.dump_pool_) { - WaitForTask(std::move(post_process_ui_traces)); - } else { - RUN_SLOW_FUNCTION_AND_LOG(POST_PROCESS_UI_TRACES_TASK, MaybePostProcessUiTraces); - } - MaybeAddUiTracesToZip(); return Dumpstate::RunStatus::OK; @@ -3078,6 +3076,7 @@ void Dumpstate::Cancel() { } void Dumpstate::PreDumpUiData() { + MaybeSnapshotSystemTrace(); MaybeSnapshotUiTraces(); } @@ -3264,25 +3263,23 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, // duration is logged into MYLOG instead. PrintHeader(); - bool is_dumpstate_restricted = options_->telephony_only - || options_->wifi_only - || options_->limited_only; - if (!is_dumpstate_restricted) { - // Invoke critical dumpsys first to preserve system state, before doing anything else. - RunDumpsysCritical(); - } - MaybeTakeEarlyScreenshot(); - + bool is_dumpstate_restricted = + options_->telephony_only || options_->wifi_only || options_->limited_only; if (!is_dumpstate_restricted) { // Snapshot the system trace now (if running) to avoid that dumpstate's // own activity pushes out interesting data from the trace ring buffer. // The trace file is added to the zip by MaybeAddSystemTraceToZip(). MaybeSnapshotSystemTrace(); + // Invoke critical dumpsys to preserve system state, before doing anything else. + RunDumpsysCritical(); + // Snapshot the UI traces now (if running). // The trace files will be added to bugreport later. MaybeSnapshotUiTraces(); } + + MaybeTakeEarlyScreenshot(); onUiIntensiveBugreportDumpsFinished(calling_uid); MaybeCheckUserConsent(calling_uid, calling_package); if (options_->telephony_only) { @@ -3379,6 +3376,19 @@ void Dumpstate::MaybeTakeEarlyScreenshot() { } void Dumpstate::MaybeSnapshotSystemTrace() { + // When capturing traces via bugreport handler (BH), this function will be invoked twice: + // 1) When BH invokes IDumpstate::PreDumpUiData() + // 2) When BH invokes IDumpstate::startBugreport(flags = BUGREPORT_USE_PREDUMPED_UI_DATA) + // In this case we don't want to re-invoke perfetto in step 2. + // In all other standard invocation states, this function is invoked once + // without the flag BUGREPORT_USE_PREDUMPED_UI_DATA. + if (options_->use_predumped_ui_data) { + return; + } + + // If a stale file exists already, remove it. + unlink(SYSTEM_TRACE_SNAPSHOT); + // If a background system trace is happening and is marked as "suitable for // bugreport" (i.e. bugreport_score > 0 in the trace config), this command // will stop it and serialize into SYSTEM_TRACE_SNAPSHOT. In the (likely) @@ -3386,14 +3396,8 @@ void Dumpstate::MaybeSnapshotSystemTrace() { // Note: this should not be enqueued as we need to freeze the trace before // dumpstate starts. Otherwise the trace ring buffers will contain mostly // the dumpstate's own activity which is irrelevant. - int res = RunCommand( - "SERIALIZE PERFETTO TRACE", - {"perfetto", "--save-for-bugreport"}, - CommandOptions::WithTimeout(10) - .DropRoot() - .CloseAllFileDescriptorsOnExec() - .Build()); - has_system_trace_ = res == 0; + RunCommand("SERIALIZE PERFETTO TRACE", {"perfetto", "--save-for-bugreport"}, + CommandOptions::WithTimeout(10).DropRoot().CloseAllFileDescriptorsOnExec().Build()); // MaybeAddSystemTraceToZip() will take care of copying the trace in the zip // file in the later stages. } @@ -3420,33 +3424,6 @@ void Dumpstate::MaybeSnapshotUiTraces() { "", command, CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); } - - // This command needs to be run as root - static const auto SURFACEFLINGER_COMMAND_SAVE_ALL_TRACES = std::vector<std::string> { - "service", "call", "SurfaceFlinger", "1042" - }; - // Empty name because it's not intended to be classified as a bugreport section. - // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport. - RunCommand( - "", SURFACEFLINGER_COMMAND_SAVE_ALL_TRACES, - CommandOptions::WithTimeout(10).Always().AsRoot().RedirectStderr().Build()); -} - -void Dumpstate::MaybePostProcessUiTraces() { - if (PropertiesHelper::IsUserBuild()) { - return; - } - - RunCommand( - // Empty name because it's not intended to be classified as a bugreport section. - // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport. - "", { - "/system/xbin/su", "system", - "/system/bin/layertracegenerator", - "/data/misc/wmtrace/transactions_trace.winscope", - "/data/misc/wmtrace/layers_trace_from_transactions.winscope" - }, - CommandOptions::WithTimeout(120).Always().RedirectStderr().Build()); } void Dumpstate::MaybeAddUiTracesToZip() { diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index d01cfcef4d..c66fd1cce6 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -476,11 +476,6 @@ class Dumpstate { // Whether it should take an screenshot earlier in the process. bool do_early_screenshot_ = false; - // This is set to true when the trace snapshot request in the early call to - // MaybeSnapshotSystemTrace(). When this is true, the later stages of - // dumpstate will append the trace to the zip archive. - bool has_system_trace_ = false; - std::unique_ptr<Progress> progress_; // When set, defines a socket file-descriptor use to report progress to bugreportz @@ -574,7 +569,6 @@ class Dumpstate { void MaybeTakeEarlyScreenshot(); void MaybeSnapshotSystemTrace(); void MaybeSnapshotUiTraces(); - void MaybePostProcessUiTraces(); void MaybeAddUiTracesToZip(); void onUiIntensiveBugreportDumpsFinished(int32_t calling_uid); diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index a417837ef9..fc828864d5 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -1000,7 +1000,6 @@ TEST_F(DumpstateTest, DumpPool_withParallelRunDisabled_isNull) { TEST_F(DumpstateTest, PreDumpUiData) { // These traces are always enabled, i.e. they are always pre-dumped const std::vector<std::filesystem::path> uiTraces = { - std::filesystem::path{"/data/misc/wmtrace/transactions_trace.winscope"}, std::filesystem::path{"/data/misc/wmtrace/wm_transition_trace.winscope"}, std::filesystem::path{"/data/misc/wmtrace/shell_transition_trace.winscope"}, }; diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index 822ab7fbb7..8eb74583fe 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -514,6 +514,8 @@ private: // Make sure dex2oat is run with background priority. dexopt_flags |= DEXOPT_BOOTCOMPLETE | DEXOPT_IDLE_BACKGROUND_JOB; + parameters_.compilation_reason = "ab-ota"; + int res = dexopt(parameters_.apk_path, parameters_.uid, parameters_.pkgName, diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp index c40caf56d8..c86adef118 100644 --- a/cmds/installd/otapreopt_chroot.cpp +++ b/cmds/installd/otapreopt_chroot.cpp @@ -353,7 +353,7 @@ static int otapreopt_chroot(const int argc, char **arg) { // Now go on and read dexopt lines from stdin and pass them on to otapreopt. int count = 1; - for (std::array<char, 1000> linebuf; + for (std::array<char, 10000> linebuf; std::cin.clear(), std::cin.getline(&linebuf[0], linebuf.size()); ++count) { // Subtract one from gcount() since getline() counts the newline. std::string line(&linebuf[0], std::cin.gcount() - 1); diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index 2e9949578d..ee7445544b 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -98,7 +98,7 @@ public: void addMovement(nsecs_t eventTime, int32_t pointerId, int32_t axis, float position); // Adds movement information for all pointers in a MotionEvent, including historical samples. - void addMovement(const MotionEvent* event); + void addMovement(const MotionEvent& event); // Returns the velocity of the specified pointer id and axis in position units per second. // Returns empty optional if there is insufficient movement information for the pointer, or if diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index f22e90a03f..824323857d 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -30,7 +30,6 @@ #include <binder/RecordedTransaction.h> #include <binder/RpcServer.h> #include <pthread.h> -#include <utils/misc.h> #include <inttypes.h> #include <stdio.h> @@ -271,7 +270,7 @@ public: bool mInheritRt = false; // for below objects - Mutex mLock; + RpcMutex mLock; std::set<sp<RpcServerLink>> mRpcServerLinks; BpBinder::ObjectManager mObjects; @@ -307,7 +306,7 @@ status_t BBinder::startRecordingTransactions(const Parcel& data) { return PERMISSION_DENIED; } Extras* e = getOrCreateExtras(); - AutoMutex lock(e->mLock); + RpcMutexUniqueLock lock(e->mLock); if (mRecordingOn) { LOG(INFO) << "Could not start Binder recording. Another is already in progress."; return INVALID_OPERATION; @@ -337,7 +336,7 @@ status_t BBinder::stopRecordingTransactions() { return PERMISSION_DENIED; } Extras* e = getOrCreateExtras(); - AutoMutex lock(e->mLock); + RpcMutexUniqueLock lock(e->mLock); if (mRecordingOn) { e->mRecordingFd.reset(); mRecordingOn = false; @@ -405,7 +404,7 @@ status_t BBinder::transact( if (kEnableKernelIpc && mRecordingOn && code != START_RECORDING_TRANSACTION) [[unlikely]] { Extras* e = mExtras.load(std::memory_order_acquire); - AutoMutex lock(e->mLock); + RpcMutexUniqueLock lock(e->mLock); if (mRecordingOn) { Parcel emptyReply; timespec ts; @@ -452,7 +451,7 @@ void* BBinder::attachObject(const void* objectID, void* object, void* cleanupCoo Extras* e = getOrCreateExtras(); LOG_ALWAYS_FATAL_IF(!e, "no memory"); - AutoMutex _l(e->mLock); + RpcMutexUniqueLock _l(e->mLock); return e->mObjects.attach(objectID, object, cleanupCookie, func); } @@ -461,7 +460,7 @@ void* BBinder::findObject(const void* objectID) const Extras* e = mExtras.load(std::memory_order_acquire); if (!e) return nullptr; - AutoMutex _l(e->mLock); + RpcMutexUniqueLock _l(e->mLock); return e->mObjects.find(objectID); } @@ -469,7 +468,7 @@ void* BBinder::detachObject(const void* objectID) { Extras* e = mExtras.load(std::memory_order_acquire); if (!e) return nullptr; - AutoMutex _l(e->mLock); + RpcMutexUniqueLock _l(e->mLock); return e->mObjects.detach(objectID); } @@ -477,7 +476,7 @@ void BBinder::withLock(const std::function<void()>& doWithLock) { Extras* e = getOrCreateExtras(); LOG_ALWAYS_FATAL_IF(!e, "no memory"); - AutoMutex _l(e->mLock); + RpcMutexUniqueLock _l(e->mLock); doWithLock(); } @@ -485,7 +484,7 @@ sp<IBinder> BBinder::lookupOrCreateWeak(const void* objectID, object_make_func m const void* makeArgs) { Extras* e = getOrCreateExtras(); LOG_ALWAYS_FATAL_IF(!e, "no memory"); - AutoMutex _l(e->mLock); + RpcMutexUniqueLock _l(e->mLock); return e->mObjects.lookupOrCreateWeak(objectID, make, makeArgs); } @@ -692,7 +691,7 @@ status_t BBinder::setRpcClientDebug(android::base::unique_fd socketFd, auto weakThis = wp<BBinder>::fromExisting(this); Extras* e = getOrCreateExtras(); - AutoMutex _l(e->mLock); + RpcMutexUniqueLock _l(e->mLock); auto rpcServer = RpcServer::make(); LOG_ALWAYS_FATAL_IF(rpcServer == nullptr, "RpcServer::make returns null"); auto link = sp<RpcServerLink>::make(rpcServer, keepAliveBinder, weakThis); @@ -716,7 +715,7 @@ status_t BBinder::setRpcClientDebug(android::base::unique_fd socketFd, void BBinder::removeRpcServerLink(const sp<RpcServerLink>& link) { Extras* e = mExtras.load(std::memory_order_acquire); if (!e) return; - AutoMutex _l(e->mLock); + RpcMutexUniqueLock _l(e->mLock); (void)e->mRpcServerLinks.erase(link); } diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 3bc4f929e7..49038b1974 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -23,7 +23,6 @@ #include <binder/IResultReceiver.h> #include <binder/RpcSession.h> #include <binder/Stability.h> -#include <utils/Log.h> #include <stdio.h> @@ -38,7 +37,7 @@ namespace android { // --------------------------------------------------------------------------- -Mutex BpBinder::sTrackingLock; +RpcMutex BpBinder::sTrackingLock; std::unordered_map<int32_t, uint32_t> BpBinder::sTrackingMap; std::unordered_map<int32_t, uint32_t> BpBinder::sLastLimitCallbackMap; int BpBinder::sNumTrackedUids = 0; @@ -163,7 +162,7 @@ sp<BpBinder> BpBinder::create(int32_t handle) { int32_t trackedUid = -1; if (sCountByUidEnabled) { trackedUid = IPCThreadState::self()->getCallingUid(); - AutoMutex _l(sTrackingLock); + RpcMutexUniqueLock _l(sTrackingLock); uint32_t trackedValue = sTrackingMap[trackedUid]; if (trackedValue & LIMIT_REACHED_MASK) [[unlikely]] { if (sBinderProxyThrottleCreate) { @@ -276,7 +275,7 @@ std::optional<int32_t> BpBinder::getDebugBinderHandle() const { } bool BpBinder::isDescriptorCached() const { - Mutex::Autolock _l(mLock); + RpcMutexUniqueLock _l(mLock); return mDescriptorCache.c_str() != kDescriptorUninit.c_str(); } @@ -292,7 +291,7 @@ const String16& BpBinder::getInterfaceDescriptor() const status_t err = thiz->transact(INTERFACE_TRANSACTION, data, &reply); if (err == NO_ERROR) { String16 res(reply.readString16()); - Mutex::Autolock _l(mLock); + RpcMutexUniqueLock _l(mLock); // mDescriptorCache could have been assigned while the lock was // released. if (mDescriptorCache.c_str() == kDescriptorUninit.c_str()) mDescriptorCache = res; @@ -385,7 +384,7 @@ status_t BpBinder::transact( status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags); } if (data.dataSize() > LOG_TRANSACTIONS_OVER_SIZE) { - Mutex::Autolock _l(mLock); + RpcMutexUniqueLock _l(mLock); ALOGW("Large outgoing transaction of %zu bytes, interface descriptor %s, code %d", data.dataSize(), String8(mDescriptorCache).c_str(), code); } @@ -431,7 +430,7 @@ status_t BpBinder::linkToDeath( "linkToDeath(): recipient must be non-NULL"); { - AutoMutex _l(mLock); + RpcMutexUniqueLock _l(mLock); if (!mObitsSent) { if (!mObituaries) { @@ -467,7 +466,7 @@ status_t BpBinder::unlinkToDeath( return INVALID_OPERATION; } - AutoMutex _l(mLock); + RpcMutexUniqueLock _l(mLock); if (mObitsSent) { return DEAD_OBJECT; @@ -555,30 +554,30 @@ void BpBinder::reportOneDeath(const Obituary& obit) void* BpBinder::attachObject(const void* objectID, void* object, void* cleanupCookie, object_cleanup_func func) { - AutoMutex _l(mLock); + RpcMutexUniqueLock _l(mLock); ALOGV("Attaching object %p to binder %p (manager=%p)", object, this, &mObjects); return mObjects.attach(objectID, object, cleanupCookie, func); } void* BpBinder::findObject(const void* objectID) const { - AutoMutex _l(mLock); + RpcMutexUniqueLock _l(mLock); return mObjects.find(objectID); } void* BpBinder::detachObject(const void* objectID) { - AutoMutex _l(mLock); + RpcMutexUniqueLock _l(mLock); return mObjects.detach(objectID); } void BpBinder::withLock(const std::function<void()>& doWithLock) { - AutoMutex _l(mLock); + RpcMutexUniqueLock _l(mLock); doWithLock(); } sp<IBinder> BpBinder::lookupOrCreateWeak(const void* objectID, object_make_func make, const void* makeArgs) { - AutoMutex _l(mLock); + RpcMutexUniqueLock _l(mLock); return mObjects.lookupOrCreateWeak(objectID, make, makeArgs); } @@ -602,7 +601,7 @@ BpBinder::~BpBinder() { IPCThreadState* ipc = IPCThreadState::self(); if (mTrackedUid >= 0) { - AutoMutex _l(sTrackingLock); + RpcMutexUniqueLock _l(sTrackingLock); uint32_t trackedValue = sTrackingMap[mTrackedUid]; if ((trackedValue & COUNTING_VALUE_MASK) == 0) [[unlikely]] { ALOGE("Unexpected Binder Proxy tracking decrement in %p handle %d\n", this, @@ -702,7 +701,7 @@ bool BpBinder::onIncStrongAttempted(uint32_t /*flags*/, const void* /*id*/) uint32_t BpBinder::getBinderProxyCount(uint32_t uid) { - AutoMutex _l(sTrackingLock); + RpcMutexUniqueLock _l(sTrackingLock); auto it = sTrackingMap.find(uid); if (it != sTrackingMap.end()) { return it->second & COUNTING_VALUE_MASK; @@ -717,7 +716,7 @@ uint32_t BpBinder::getBinderProxyCount() void BpBinder::getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts) { - AutoMutex _l(sTrackingLock); + RpcMutexUniqueLock _l(sTrackingLock); uids.setCapacity(sTrackingMap.size()); counts.setCapacity(sTrackingMap.size()); for (const auto& it : sTrackingMap) { @@ -731,12 +730,12 @@ void BpBinder::disableCountByUid() { sCountByUidEnabled.store(false); } void BpBinder::setCountByUidEnabled(bool enable) { sCountByUidEnabled.store(enable); } void BpBinder::setLimitCallback(binder_proxy_limit_callback cb) { - AutoMutex _l(sTrackingLock); + RpcMutexUniqueLock _l(sTrackingLock); sLimitCallback = cb; } void BpBinder::setBinderProxyCountWatermarks(int high, int low) { - AutoMutex _l(sTrackingLock); + RpcMutexUniqueLock _l(sTrackingLock); sBinderProxyCountHighWatermark = high; sBinderProxyCountLowWatermark = low; } diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp index c6e4fb378d..7ae616e2b0 100644 --- a/libs/binder/Debug.cpp +++ b/libs/binder/Debug.cpp @@ -19,8 +19,6 @@ #include <binder/ProcessState.h> -#include <utils/misc.h> - #include <stdio.h> #include <stdlib.h> #include <ctype.h> diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp index 2780bd4cd9..dea26038cf 100644 --- a/libs/binder/IInterface.cpp +++ b/libs/binder/IInterface.cpp @@ -15,7 +15,6 @@ */ #define LOG_TAG "IInterface" -#include <utils/Log.h> #include <binder/IInterface.h> namespace android { diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp index cd92217f84..60ece7269c 100644 --- a/libs/binder/IResultReceiver.cpp +++ b/libs/binder/IResultReceiver.cpp @@ -18,7 +18,6 @@ #include <binder/IResultReceiver.h> -#include <utils/Log.h> #include <binder/Parcel.h> #include <utils/String8.h> diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 6034f2b4ca..fe566fccb2 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -200,7 +200,7 @@ bool checkCallingPermission(const String16& permission, int32_t* outPid, int32_t } bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logPermissionFailure) { - static Mutex gPermissionControllerLock; + static std::mutex gPermissionControllerLock; static sp<IPermissionController> gPermissionController; sp<IPermissionController> pc; diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp index 5b1cb7ea56..95bdbb4b65 100644 --- a/libs/binder/MemoryDealer.cpp +++ b/libs/binder/MemoryDealer.cpp @@ -155,7 +155,7 @@ private: void dump_l(String8& res, const char* what) const; static const int kMemoryAlign; - mutable Mutex mLock; + mutable std::mutex mLock; LinkedList<chunk_t> mList; size_t mHeapSize; }; @@ -305,14 +305,14 @@ size_t SimpleBestFitAllocator::size() const size_t SimpleBestFitAllocator::allocate(size_t size, uint32_t flags) { - Mutex::Autolock _l(mLock); + std::unique_lock<std::mutex> _l(mLock); ssize_t offset = alloc(size, flags); return offset; } status_t SimpleBestFitAllocator::deallocate(size_t offset) { - Mutex::Autolock _l(mLock); + std::unique_lock<std::mutex> _l(mLock); chunk_t const * const freed = dealloc(offset); if (freed) { return NO_ERROR; @@ -420,7 +420,7 @@ SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start) void SimpleBestFitAllocator::dump(const char* what) const { - Mutex::Autolock _l(mLock); + std::unique_lock<std::mutex> _l(mLock); dump_l(what); } @@ -434,7 +434,7 @@ void SimpleBestFitAllocator::dump_l(const char* what) const void SimpleBestFitAllocator::dump(String8& result, const char* what) const { - Mutex::Autolock _l(mLock); + std::unique_lock<std::mutex> _l(mLock); dump_l(result, what); } diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index a3ff7d258b..6d2e12b54e 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "Parcel" //#define LOG_NDEBUG 0 +#include <endian.h> #include <errno.h> #include <fcntl.h> #include <inttypes.h> @@ -43,11 +44,8 @@ #ifndef BINDER_DISABLE_BLOB #include <cutils/ashmem.h> #endif -#include <utils/Flattenable.h> -#include <utils/Log.h> #include <utils/String16.h> #include <utils/String8.h> -#include <utils/misc.h> #include "OS.h" #include "RpcState.h" diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 8ec4af9945..58203c1373 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -189,7 +189,7 @@ void ProcessState::childPostFork() { void ProcessState::startThreadPool() { - AutoMutex _l(mLock); + std::unique_lock<std::mutex> _l(mLock); if (!mThreadPoolStarted) { if (mMaxThreads == 0) { // see also getThreadPoolMaxTotalThreadCount @@ -203,7 +203,7 @@ void ProcessState::startThreadPool() bool ProcessState::becomeContextManager() { - AutoMutex _l(mLock); + std::unique_lock<std::mutex> _l(mLock); flat_binder_object obj { .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX, @@ -310,7 +310,7 @@ sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) { sp<IBinder> result; - AutoMutex _l(mLock); + std::unique_lock<std::mutex> _l(mLock); if (handle == 0 && the_context_object != nullptr) return the_context_object; @@ -374,7 +374,7 @@ sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) void ProcessState::expungeHandle(int32_t handle, IBinder* binder) { - AutoMutex _l(mLock); + std::unique_lock<std::mutex> _l(mLock); handle_entry* e = lookupHandleLocked(handle); diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 07ab093992..1011571408 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -30,7 +30,6 @@ #include <binder/RpcServer.h> #include <binder/RpcTransportRaw.h> #include <log/log.h> -#include <utils/Compat.h> #include "BuildFlags.h" #include "FdTrigger.h" diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index fa8f2b51ac..c8aff63078 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -33,7 +33,6 @@ #include <binder/RpcServer.h> #include <binder/RpcTransportRaw.h> #include <binder/Stability.h> -#include <utils/Compat.h> #include <utils/String8.h> #include "BuildFlags.h" diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 5046253837..749c2f81ea 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -20,7 +20,6 @@ #include <android-base/macros.h> #include <android-base/scopeguard.h> -#include <android-base/stringprintf.h> #include <binder/BpBinder.h> #include <binder/IPCThreadState.h> #include <binder/RpcServer.h> @@ -30,6 +29,7 @@ #include "Utils.h" #include <random> +#include <sstream> #include <inttypes.h> @@ -39,8 +39,6 @@ namespace android { -using base::StringPrintf; - #if RPC_FLAKE_PRONE void rpcMaybeWaitToFlake() { [[clang::no_destroy]] static std::random_device r; @@ -329,8 +327,10 @@ std::string RpcState::BinderNode::toString() const { desc = "(not promotable)"; } - return StringPrintf("node{%p times sent: %zu times recd: %zu type: %s}", - this->binder.unsafe_get(), this->timesSent, this->timesRecd, desc); + std::stringstream ss; + ss << "node{" << intptr_t(this->binder.unsafe_get()) << " times sent: " << this->timesSent + << " times recd: " << this->timesRecd << " type: " << desc << "}"; + return ss.str(); } RpcState::CommandData::CommandData(size_t size) : mSize(size) { @@ -412,10 +412,8 @@ bool RpcState::validateProtocolVersion(uint32_t version) { return false; } #else - // TODO(b/305983144) - // don't restrict on other platforms, though experimental should - // only really be used for testing, we don't have a good way to see - // what is shipping outside of Android + ALOGE("Cannot use experimental RPC binder protocol outside of Android."); + return false; #endif } else if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT) { ALOGE("Cannot use RPC binder protocol version %u which is unknown (current protocol " @@ -1220,10 +1218,11 @@ status_t RpcState::validateParcel(const sp<RpcSession>& session, const Parcel& p uint32_t protocolVersion = session->getProtocolVersion().value(); if (protocolVersion < RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE && !rpcFields->mObjectPositions.empty()) { - *errorMsg = StringPrintf("Parcel has attached objects but the session's protocol version " - "(%" PRIu32 ") is too old, must be at least %" PRIu32, - protocolVersion, - RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE); + std::stringstream ss; + ss << "Parcel has attached objects but the session's protocol version (" << protocolVersion + << ") is too old, must be at least " + << RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE; + *errorMsg = ss.str(); return BAD_VALUE; } @@ -1236,9 +1235,10 @@ status_t RpcState::validateParcel(const sp<RpcSession>& session, const Parcel& p case RpcSession::FileDescriptorTransportMode::UNIX: { constexpr size_t kMaxFdsPerMsg = 253; if (rpcFields->mFds->size() > kMaxFdsPerMsg) { - *errorMsg = StringPrintf("Too many file descriptors in Parcel for unix " - "domain socket: %zu (max is %zu)", - rpcFields->mFds->size(), kMaxFdsPerMsg); + std::stringstream ss; + ss << "Too many file descriptors in Parcel for unix domain socket: " + << rpcFields->mFds->size() << " (max is " << kMaxFdsPerMsg << ")"; + *errorMsg = ss.str(); return BAD_VALUE; } break; @@ -1249,9 +1249,10 @@ status_t RpcState::validateParcel(const sp<RpcSession>& session, const Parcel& p // available on Android constexpr size_t kMaxFdsPerMsg = 8; if (rpcFields->mFds->size() > kMaxFdsPerMsg) { - *errorMsg = StringPrintf("Too many file descriptors in Parcel for Trusty " - "IPC connection: %zu (max is %zu)", - rpcFields->mFds->size(), kMaxFdsPerMsg); + std::stringstream ss; + ss << "Too many file descriptors in Parcel for Trusty IPC connection: " + << rpcFields->mFds->size() << " (max is " << kMaxFdsPerMsg << ")"; + *errorMsg = ss.str(); return BAD_VALUE; } break; diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h index dd632c0b26..8942c31c48 100644 --- a/libs/binder/Utils.h +++ b/libs/binder/Utils.h @@ -22,6 +22,19 @@ #include <log/log.h> #include <utils/Errors.h> +/* TEMP_FAILURE_RETRY is not available on macOS and Trusty. */ +#ifndef TEMP_FAILURE_RETRY +/* Used to retry syscalls that can return EINTR. */ +#define TEMP_FAILURE_RETRY(exp) \ + ({ \ + __typeof__(exp) _rc; \ + do { \ + _rc = (exp); \ + } while (_rc == -1 && errno == EINTR); \ + _rc; \ + }) +#endif + #define TEST_AND_RETURN(value, expr) \ do { \ if (!(expr)) { \ diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 28fb9f1bbc..d78ea0d6b1 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -18,7 +18,7 @@ #include <android-base/unique_fd.h> #include <binder/IBinder.h> -#include <utils/Mutex.h> +#include <binder/RpcThreads.h> #include <map> #include <optional> @@ -193,7 +193,7 @@ private: void reportOneDeath(const Obituary& obit); bool isDescriptorCached() const; - mutable Mutex mLock; + mutable RpcMutex mLock; volatile int32_t mAlive; volatile int32_t mObitsSent; Vector<Obituary>* mObituaries; @@ -201,7 +201,7 @@ private: mutable String16 mDescriptorCache; int32_t mTrackedUid; - static Mutex sTrackingLock; + static RpcMutex sTrackingLock; static std::unordered_map<int32_t,uint32_t> sTrackingMap; static int sNumTrackedUids; static std::atomic_bool sCountByUidEnabled; diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 98d12bb120..6961abc64b 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -33,7 +33,6 @@ #include <utils/RefBase.h> #include <utils/String16.h> #include <utils/Vector.h> -#include <utils/Flattenable.h> #include <binder/IInterface.h> #include <binder/Parcelable.h> diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index 9dc370b412..3672702fe1 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -17,13 +17,13 @@ #pragma once #include <binder/IBinder.h> -#include <utils/KeyedVector.h> -#include <utils/Mutex.h> #include <utils/String16.h> #include <utils/String8.h> #include <pthread.h> +#include <mutex> + // --------------------------------------------------------------------------- namespace android { @@ -178,7 +178,7 @@ private: // Time when thread pool was emptied int64_t mStarvationStartTimeMs; - mutable Mutex mLock; // protects everything below. + mutable std::mutex mLock; // protects everything below. Vector<handle_entry> mHandleToObject; diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp index 5bf9680284..f2693dda95 100644 --- a/libs/binder/servicedispatcher.cpp +++ b/libs/binder/servicedispatcher.cpp @@ -22,7 +22,6 @@ #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/properties.h> -#include <android-base/stringprintf.h> #include <android/debug/BnAdbCallback.h> #include <android/debug/IAdbManager.h> #include <android/os/BnServiceManager.h> @@ -46,7 +45,6 @@ using android::base::LogdLogger; using android::base::LogId; using android::base::LogSeverity; using android::base::StdioLogger; -using android::base::StringPrintf; using std::string_view_literals::operator""sv; namespace { @@ -57,11 +55,12 @@ using android::debug::IAdbManager; int Usage(const char* program) { auto basename = Basename(program); - auto format = R"(dispatch calls to RPC service. + // clang-format off + LOG(ERROR) << R"(dispatch calls to RPC service. Usage: - %s [-g] [-i <ip_address>] <service_name> + )" << basename << R"( [-g] [-i <ip_address>] <service_name> <service_name>: the service to connect to. - %s [-g] manager + )" << basename << R"( [-g] manager Runs an RPC-friendly service that redirects calls to servicemanager. -g: use getService() instead of checkService(). @@ -71,7 +70,7 @@ Usage: blocks until killed. Otherwise, writes error message to stderr and exits with non-zero code. )"; - LOG(ERROR) << StringPrintf(format, basename.c_str(), basename.c_str()); + // clang-format on return EX_USAGE; } diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 341e9ce5ec..659943a718 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -40,6 +40,7 @@ #include <binder/IServiceManager.h> #include <binder/RpcServer.h> #include <binder/RpcSession.h> +#include <utils/Flattenable.h> #include <linux/sched.h> #include <sys/epoll.h> diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 1340ea1d2c..bc34d4c36f 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -18,7 +18,6 @@ // only used on NDK tests outside of vendor #include <aidl/IBinderRpcTest.h> #endif -#include <android-base/stringprintf.h> #include <chrono> #include <cstdlib> @@ -59,12 +58,12 @@ constexpr char kTrustyIpcDevice[] = "/dev/trusty-ipc-dev0"; static std::string WaitStatusToString(int wstatus) { if (WIFEXITED(wstatus)) { - return base::StringPrintf("exit status %d", WEXITSTATUS(wstatus)); + return std::format("exit status {}", WEXITSTATUS(wstatus)); } if (WIFSIGNALED(wstatus)) { - return base::StringPrintf("term signal %d", WTERMSIG(wstatus)); + return std::format("term signal {}", WTERMSIG(wstatus)); } - return base::StringPrintf("unexpected state %d", wstatus); + return std::format("unexpected state {}", wstatus); } static void debugBacktrace(pid_t pid) { @@ -260,9 +259,9 @@ std::unique_ptr<ProcessSession> BinderRpc::createRpcTestSocketServerProcessEtc( bool noKernel = GetParam().noKernel; std::string path = android::base::GetExecutableDirectory(); - auto servicePath = android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(), - singleThreaded ? "_single_threaded" : "", - noKernel ? "_no_kernel" : ""); + auto servicePath = + std::format("{}/binder_rpc_test_service{}{}", path, + singleThreaded ? "_single_threaded" : "", noKernel ? "_no_kernel" : ""); base::unique_fd bootstrapClientFd, socketFd; diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h index eceff35e3e..c3070ddd14 100644 --- a/libs/binder/tests/binderRpcTestCommon.h +++ b/libs/binder/tests/binderRpcTestCommon.h @@ -22,7 +22,6 @@ #include <BnBinderRpcCallback.h> #include <BnBinderRpcSession.h> #include <BnBinderRpcTest.h> -#include <android-base/stringprintf.h> #include <binder/Binder.h> #include <binder/BpBinder.h> #include <binder/IPCThreadState.h> @@ -58,6 +57,7 @@ #include "../BuildFlags.h" #include "../FdTrigger.h" #include "../RpcState.h" // for debugging +#include "format.h" #include "utils/Errors.h" namespace android { @@ -74,8 +74,7 @@ static inline bool hasExperimentalRpc() { #ifdef __ANDROID__ return base::GetProperty("ro.build.version.codename", "") != "REL"; #else - // TODO(b/305983144): restrict on other platforms - return true; + return false; #endif } @@ -91,7 +90,7 @@ static inline std::vector<uint32_t> testVersions() { } static inline std::string trustyIpcPort(uint32_t serverVersion) { - return base::StringPrintf("com.android.trusty.binderRpcTestService.V%" PRIu32, serverVersion); + return std::format("com.android.trusty.binderRpcTestService.V{}", serverVersion); } enum class SocketType { diff --git a/libs/binder/tests/binderRpcTestServiceTrusty.cpp b/libs/binder/tests/binderRpcTestServiceTrusty.cpp index cb632e95bf..aaca8d091a 100644 --- a/libs/binder/tests/binderRpcTestServiceTrusty.cpp +++ b/libs/binder/tests/binderRpcTestServiceTrusty.cpp @@ -16,7 +16,6 @@ #define TLOG_TAG "binderRpcTestService" -#include <android-base/stringprintf.h> #include <binder/RpcServerTrusty.h> #include <inttypes.h> #include <lib/tipc/tipc.h> @@ -28,7 +27,6 @@ #include "binderRpcTestCommon.h" using namespace android; -using android::base::StringPrintf; using binder::Status; static int gConnectionCounter = 0; diff --git a/libs/binder/tests/binderRpcTestTrusty.cpp b/libs/binder/tests/binderRpcTestTrusty.cpp index fcb83bdabd..8acaae6e95 100644 --- a/libs/binder/tests/binderRpcTestTrusty.cpp +++ b/libs/binder/tests/binderRpcTestTrusty.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "binderRpcTest" -#include <android-base/stringprintf.h> #include <binder/RpcTransportTipcTrusty.h> #include <trusty-gtest.h> #include <trusty_ipc.h> diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp index 1c13866626..cbbbe74bb5 100644 --- a/libs/binder/tests/binderSafeInterfaceTest.cpp +++ b/libs/binder/tests/binderSafeInterfaceTest.cpp @@ -28,6 +28,7 @@ #include <gtest/gtest.h> #pragma clang diagnostic pop +#include <utils/Flattenable.h> #include <utils/LightRefBase.h> #include <utils/NativeHandle.h> diff --git a/libs/gui/include/gui/Flags.h b/libs/binder/tests/format.h index a2cff56e97..b5440a43e4 100644 --- a/libs/gui/include/gui/Flags.h +++ b/libs/binder/tests/format.h @@ -1,5 +1,5 @@ /* - * Copyright 2023 The Android Open Source Project + * Copyright (C) 2023 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. @@ -14,9 +14,16 @@ * limitations under the License. */ -#pragma once +// TODO(b/302723053): remove this header and replace with <format> once b/175635923 is done +// ETA for this blocker is 2023-10-27~2023-11-10. +// Also, remember to remove fmtlib's format.cc from trusty makefiles. -// TODO(281695725): replace this with build time flags, whenever they are available -#ifndef FLAG_BQ_SET_FRAME_RATE -#define FLAG_BQ_SET_FRAME_RATE false +#if __has_include(<format>) +#include <format> +#else +#include <fmt/format.h> + +namespace std { +using fmt::format; +} #endif
\ No newline at end of file diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp index 416ffad466..ffeca2d13e 100644 --- a/libs/binder/tests/parcel_fuzzer/binder.cpp +++ b/libs/binder/tests/parcel_fuzzer/binder.cpp @@ -25,6 +25,7 @@ #include <binder/ParcelableHolder.h> #include <binder/PersistableBundle.h> #include <binder/Status.h> +#include <utils/Flattenable.h> #include "../../Utils.h" diff --git a/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp b/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp index e494366267..f3006cdeee 100644 --- a/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp +++ b/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp @@ -35,7 +35,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (transaction.has_value()) { intermediateFile = std::tmpfile(); - android::base::unique_fd fdForWriting(fileno(intermediateFile)); + android::base::unique_fd fdForWriting(dup(fileno(intermediateFile))); auto writeStatus ATTRIBUTE_UNUSED = transaction.value().dumpToFile(fdForWriting); std::fclose(intermediateFile); diff --git a/libs/binder/trusty/binderRpcTest/rules.mk b/libs/binder/trusty/binderRpcTest/rules.mk index 975f689d1a..e46ccfb967 100644 --- a/libs/binder/trusty/binderRpcTest/rules.mk +++ b/libs/binder/trusty/binderRpcTest/rules.mk @@ -21,6 +21,7 @@ MODULE := $(LOCAL_DIR) MANIFEST := $(LOCAL_DIR)/manifest.json MODULE_SRCS += \ + $(FMTLIB_DIR)/src/format.cc \ $(LIBBINDER_TESTS_DIR)/binderRpcUniversalTests.cpp \ $(LIBBINDER_TESTS_DIR)/binderRpcTestCommon.cpp \ $(LIBBINDER_TESTS_DIR)/binderRpcTestTrusty.cpp \ diff --git a/libs/binder/trusty/binderRpcTest/service/rules.mk b/libs/binder/trusty/binderRpcTest/service/rules.mk index 5d1a51dca2..50ae3d25fa 100644 --- a/libs/binder/trusty/binderRpcTest/service/rules.mk +++ b/libs/binder/trusty/binderRpcTest/service/rules.mk @@ -21,6 +21,7 @@ MODULE := $(LOCAL_DIR) MANIFEST := $(LOCAL_DIR)/manifest.json MODULE_SRCS := \ + $(FMTLIB_DIR)/src/format.cc \ $(LIBBINDER_TESTS_DIR)/binderRpcTestCommon.cpp \ $(LIBBINDER_TESTS_DIR)/binderRpcTestServiceTrusty.cpp \ diff --git a/libs/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp index d4605ea13a..3fe71cefce 100644 --- a/libs/bufferqueueconverter/Android.bp +++ b/libs/bufferqueueconverter/Android.bp @@ -34,5 +34,7 @@ cc_library { "libbase", "liblog", ], + static_libs: ["libguiflags"], export_include_dirs: ["include"], + export_static_lib_headers: ["libguiflags"], } diff --git a/libs/bufferstreams/examples/app/Android.bp b/libs/bufferstreams/examples/app/Android.bp index 0ecf94c48d..d6305f895c 100644 --- a/libs/bufferstreams/examples/app/Android.bp +++ b/libs/bufferstreams/examples/app/Android.bp @@ -14,14 +14,33 @@ android_app { name: "BufferStreamsDemoApp", - srcs: ["java/**/*.java"], + srcs: ["java/**/*.kt"], sdk_version: "current", jni_uses_platform_apis: true, jni_libs: ["libbufferstreamdemoapp"], use_embedded_native_libs: true, + kotlincflags: [ + "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api", + ], + + resource_dirs: ["res"], static_libs: [ + "androidx.activity_activity-compose", "androidx.appcompat_appcompat", + "androidx.compose.foundation_foundation", + "androidx.compose.material3_material3", + "androidx.compose.runtime_runtime", + "androidx.compose.ui_ui", + "androidx.compose.ui_ui-graphics", + "androidx.compose.ui_ui-tooling-preview", + "androidx.core_core-ktx", + "androidx.lifecycle_lifecycle-runtime-ktx", + "androidx.navigation_navigation-common-ktx", + "androidx.navigation_navigation-compose", + "androidx.navigation_navigation-fragment-ktx", + "androidx.navigation_navigation-runtime-ktx", + "androidx.navigation_navigation-ui-ktx", ], } diff --git a/libs/bufferstreams/examples/app/AndroidManifest.xml b/libs/bufferstreams/examples/app/AndroidManifest.xml index 872193c4e6..a5e2fa8a63 100644 --- a/libs/bufferstreams/examples/app/AndroidManifest.xml +++ b/libs/bufferstreams/examples/app/AndroidManifest.xml @@ -9,14 +9,15 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/Theme.AppCompat.Light" + android:theme="@style/Theme.Jetpack" tools:targetApi="34"> <activity android:name=".MainActivity" - android:exported="true"> + android:exported="true" + android:label="@string/app_name" + android:theme="@style/Theme.Jetpack"> <intent-filter> <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt new file mode 100644 index 0000000000..ff3ae5a090 --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt @@ -0,0 +1,40 @@ +package com.android.graphics.bufferstreamsdemoapp + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource + +@Composable +fun BufferDemosAppBar( + currentScreen: BufferDemoScreen, + canNavigateBack: Boolean, + navigateUp: () -> Unit, + modifier: Modifier = Modifier +) { + TopAppBar( + title = { Text(stringResource(currentScreen.title)) }, + colors = + TopAppBarDefaults.mediumTopAppBarColors( + containerColor = MaterialTheme.colorScheme.primaryContainer + ), + modifier = modifier, + navigationIcon = { + if (canNavigateBack) { + IconButton(onClick = navigateUp) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(R.string.back_button) + ) + } + } + } + ) +}
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferStreamJNI.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferStreamJNI.kt new file mode 100644 index 0000000000..a2db9349aa --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferStreamJNI.kt @@ -0,0 +1,27 @@ +package com.android.graphics.bufferstreamsdemoapp + +class BufferStreamJNI { + // Used to load the 'bufferstreamsdemoapp' library on application startup. + init { + System.loadLibrary("bufferstreamdemoapp") + } + + /** + * A native method that is implemented by the 'bufferstreamsdemoapp' native library, which is + * packaged with this application. + */ + external fun stringFromJNI() + external fun testBufferQueueCreation() + + companion object { + fun companion_stringFromJNI() { + val instance = BufferStreamJNI() + instance.stringFromJNI() + } + + fun companion_testBufferQueueCreation() { + val instance = BufferStreamJNI() + instance.testBufferQueueCreation() + } + } +}
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen1.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen1.kt new file mode 100644 index 0000000000..46ce0283b4 --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen1.kt @@ -0,0 +1,33 @@ +package com.android.graphics.bufferstreamsdemoapp + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.Card +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun DemoScreen1(modifier: Modifier = Modifier) { + Column(modifier = modifier, verticalArrangement = Arrangement.SpaceBetween) { + Card(modifier = Modifier.fillMaxWidth().weight(1f, false).padding(16.dp).height(400.dp)) { + Text("Log output", modifier = Modifier.padding(16.dp)) + } + Row(modifier = Modifier.weight(1f, false).padding(16.dp)) { + Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { + Button( + modifier = Modifier.fillMaxWidth(), + onClick = { BufferStreamJNI.companion_testBufferQueueCreation() } + ) { Text("Run") } + OutlinedButton(modifier = Modifier.fillMaxWidth(), onClick = {}) { Text("Clear") } + } + } + } +}
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen2.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen2.kt new file mode 100644 index 0000000000..5efee92f76 --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen2.kt @@ -0,0 +1,7 @@ +package com.android.graphics.bufferstreamsdemoapp + +import androidx.compose.runtime.Composable + +@Composable +fun DemoScreen2() { +}
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen3.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen3.kt new file mode 100644 index 0000000000..8cba857737 --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen3.kt @@ -0,0 +1,7 @@ +package com.android.graphics.bufferstreamsdemoapp + +import androidx.compose.runtime.Composable + +@Composable +fun DemoScreen3() { +}
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.java b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.java deleted file mode 100644 index 67b95a5349..0000000000 --- a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.java +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2023 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 com.android.graphics.bufferstreamsdemoapp; - -import android.os.Bundle; -import android.widget.TextView; -import androidx.appcompat.app.AppCompatActivity; - -public class MainActivity extends AppCompatActivity { - // Used to load the 'bufferstreamsdemoapp' library on application startup. - static { System.loadLibrary("bufferstreamdemoapp"); } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - RunBufferQueue(); - System.out.println("stringFromJNI: " + stringFromJNI()); - } - - /** - * A native method that is implemented by the 'bufferstreamsdemoapp' native - * library, which is packaged with this application. - */ - public native String stringFromJNI(); - public native void RunBufferQueue(); -}
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.kt new file mode 100644 index 0000000000..f3f440482f --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.kt @@ -0,0 +1,136 @@ +package com.android.graphics.bufferstreamsdemoapp + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.annotation.StringRes +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.material3.Button +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController +import com.android.graphics.bufferstreamsdemoapp.ui.theme.JetpackTheme + +class MainActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + JetpackTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { BufferDemosApp() } + } + } + } +} + +enum class BufferDemoScreen(val route: String, @StringRes val title: Int) { + Start(route = "start", title = R.string.start), + Demo1(route = "demo1", title = R.string.demo1), + Demo2(route = "demo2", title = R.string.demo2), + Demo3(route = "demo3", title = R.string.demo3); + + companion object { + fun findByRoute(route: String): BufferDemoScreen { + return values().find { it.route == route }!! + } + } +} + +@Composable +fun BufferDemosApp() { + var navController: NavHostController = rememberNavController() + // Get current back stack entry + val backStackEntry by navController.currentBackStackEntryAsState() + // Get the name of the current screen + val currentScreen = + BufferDemoScreen.findByRoute( + backStackEntry?.destination?.route ?: BufferDemoScreen.Start.route + ) + + Scaffold( + topBar = { + BufferDemosAppBar( + currentScreen = currentScreen, + canNavigateBack = navController.previousBackStackEntry != null, + navigateUp = { navController.navigateUp() } + ) + } + ) { + NavHost( + navController = navController, + startDestination = BufferDemoScreen.Start.route, + modifier = Modifier.padding(10.dp) + ) { + composable(route = BufferDemoScreen.Start.route) { + DemoList( + onButtonClicked = { + navController.navigate(it) + }, + ) + } + composable(route = BufferDemoScreen.Demo1.route) { + DemoScreen1(modifier = Modifier.fillMaxHeight().padding(top = 100.dp)) + } + composable(route = BufferDemoScreen.Demo2.route) { DemoScreen2() } + composable(route = BufferDemoScreen.Demo3.route) { DemoScreen3() } + } + } +} + +@Composable +fun DemoList(onButtonClicked: (String) -> Unit) { + var modifier = Modifier.fillMaxSize().padding(16.dp) + + Column(modifier = modifier, verticalArrangement = Arrangement.SpaceBetween) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Spacer(modifier = Modifier.height(100.dp)) + Text(text = "Buffer Demos", style = MaterialTheme.typography.titleLarge) + Spacer(modifier = Modifier.height(8.dp)) + } + Row(modifier = Modifier.weight(2f, false)) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + for (item in BufferDemoScreen.values()) { + if (item.route != BufferDemoScreen.Start.route) + SelectDemoButton(name = stringResource(item.title), onClick = { onButtonClicked(item.route) }) + } + } + } + } +} + +@Composable +fun SelectDemoButton(name: String, onClick: () -> Unit, modifier: Modifier = Modifier) { + Button(onClick = onClick, modifier = modifier.widthIn(min = 250.dp)) { Text(name) } +} diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Color.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Color.kt new file mode 100644 index 0000000000..d85ea724de --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Color.kt @@ -0,0 +1,11 @@ +package com.android.graphics.bufferstreamsdemoapp.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260)
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Theme.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Theme.kt new file mode 100644 index 0000000000..fccd93a10b --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Theme.kt @@ -0,0 +1,60 @@ +package com.android.graphics.bufferstreamsdemoapp.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 +) + +@Composable +fun JetpackTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.primary.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +}
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Type.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Type.kt new file mode 100644 index 0000000000..06814ead8b --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Type.kt @@ -0,0 +1,18 @@ +package com.android.graphics.bufferstreamsdemoapp.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) +)
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/jni/main.cpp b/libs/bufferstreams/examples/app/jni/main.cpp index 34e0eb451c..3d3fee4c6a 100644 --- a/libs/bufferstreams/examples/app/jni/main.cpp +++ b/libs/bufferstreams/examples/app/jni/main.cpp @@ -19,16 +19,16 @@ extern "C" { JNIEXPORT jstring JNICALL - Java_com_android_graphics_bufferstreamsdemoapp_MainActivity_stringFromJNI( - JNIEnv *env, + Java_com_android_graphics_bufferstreamsdemoapp_BufferStreamJNI_stringFromJNI( + JNIEnv* env, jobject /* this */) { const char* hello = "Hello from C++"; return env->NewStringUTF(hello); } JNIEXPORT void JNICALL - Java_com_android_graphics_bufferstreamsdemoapp_MainActivity_RunBufferQueue( - JNIEnv *env, + Java_com_android_graphics_bufferstreamsdemoapp_BufferStreamJNI_testBufferQueueCreation( + JNIEnv* /* env */, jobject /* this */) { android::sp<android::IGraphicBufferProducer> producer; android::sp<android::IGraphicBufferConsumer> consumer; diff --git a/libs/bufferstreams/examples/app/res/layout/activity_main.xml b/libs/bufferstreams/examples/app/res/layout/activity_main.xml deleted file mode 100644 index 79fb331f09..0000000000 --- a/libs/bufferstreams/examples/app/res/layout/activity_main.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<androidx.constraintlayout.widget.ConstraintLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - xmlns:tools="http://schemas.android.com/tools" - android:layout_width="match_parent" - android:layout_height="match_parent" - tools:context=".MainActivity"> - - <TextView - android:id="@+id/sample_text" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="Hello World!" - tools:layout_editor_absoluteX="100dp" - tools:layout_editor_absoluteY="100dp" /> - -</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/res/values/strings.xml b/libs/bufferstreams/examples/app/res/values/strings.xml index e652102cb3..75c8ab5e1c 100644 --- a/libs/bufferstreams/examples/app/res/values/strings.xml +++ b/libs/bufferstreams/examples/app/res/values/strings.xml @@ -1,3 +1,8 @@ <resources> <string name="app_name">Buffer Demos</string> + <string name="start">Start</string> + <string name="demo1">Demo 1</string> + <string name="demo2">Demo 2</string> + <string name="demo3">Demo 3</string> + <string name="back_button">Back</string> </resources>
\ No newline at end of file diff --git a/libs/bufferstreams/examples/app/res/values/themes.xml b/libs/bufferstreams/examples/app/res/values/themes.xml new file mode 100644 index 0000000000..eeb308ae44 --- /dev/null +++ b/libs/bufferstreams/examples/app/res/values/themes.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="Theme.Jetpack" parent="android:Theme.Material.Light.NoActionBar" /> +</resources>
\ No newline at end of file diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h index 9ebaf16eb4..47607a0ab9 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -104,7 +104,7 @@ public: GL_UPDATED = 2, VULKAN = 3, VULKAN_UPDATED = 4, - ANGLE = 5, // cover both system ANGLE and ANGLE APK + ANGLE = 5, }; enum Stats { diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index f17a6547f7..c84ee1f9da 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -20,6 +20,25 @@ package { default_applicable_licenses: ["frameworks_native_license"], } +aconfig_declarations { + name: "libgui_flags", + package: "com.android.graphics.libgui.flags", + srcs: ["libgui_flags.aconfig"], +} + +cc_aconfig_library { + name: "libguiflags", + host_supported: true, + vendor_available: true, + min_sdk_version: "29", + apex_available: [ + "//apex_available:platform", + "com.android.media.swcodec", + "test_com.android.media.swcodec", + ], + aconfig_declarations: "libgui_flags", +} + cc_library_headers { name: "libgui_headers", vendor_available: true, @@ -36,6 +55,8 @@ cc_library_headers { "android.hardware.graphics.bufferqueue@1.0", "android.hardware.graphics.bufferqueue@2.0", ], + static_libs: ["libguiflags"], + export_static_lib_headers: ["libguiflags"], min_sdk_version: "29", // TODO(b/218719284) can media use be constrained to libgui_bufferqueue_static? apex_available: [ @@ -192,19 +213,6 @@ cc_library_static { }, } -aconfig_declarations { - name: "libgui_flags", - package: "com.android.graphics.libgui.flags", - srcs: ["libgui_flags.aconfig"], -} - -cc_aconfig_library { - name: "libguiflags", - host_supported: true, - vendor_available: true, - aconfig_declarations: "libgui_flags", -} - filegroup { name: "libgui-sources", srcs: [ @@ -265,6 +273,9 @@ cc_defaults { "libbinder", "libGLESv2", ], + export_static_lib_headers: [ + "libguiflags", + ], } cc_library_shared { @@ -460,6 +471,7 @@ cc_library_static { static_libs: [ "libgtest", "libgmock", + "libguiflags", ], srcs: [ diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index dd0a028865..8d0331ebb5 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -26,7 +26,7 @@ #include <gui/BufferQueueConsumer.h> #include <gui/BufferQueueCore.h> #include <gui/BufferQueueProducer.h> -#include <gui/Flags.h> + #include <gui/FrameRateUtils.h> #include <gui/GLConsumer.h> #include <gui/IProducerListener.h> @@ -41,8 +41,6 @@ #include <android-base/thread_annotations.h> #include <chrono> -#include <com_android_graphics_libgui_flags.h> - using namespace com::android::graphics::libgui; using namespace std::chrono_literals; @@ -144,7 +142,7 @@ void BLASTBufferItemConsumer::onSidebandStreamChanged() { } } -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) void BLASTBufferItemConsumer::onSetFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) { sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote(); diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index ab0f6d213f..b0f6e69115 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -22,7 +22,6 @@ #include <gui/BufferQueueConsumer.h> #include <gui/BufferQueueCore.h> #include <gui/BufferQueueProducer.h> -#include <gui/Flags.h> namespace android { @@ -99,7 +98,7 @@ void BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps( } } -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) void BufferQueue::ProxyConsumerListener::onSetFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) { sp<ConsumerListener> listener(mConsumerListener.promote()); diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 67dff6dec6..19693e37cf 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -32,7 +32,7 @@ #include <gui/BufferItem.h> #include <gui/BufferQueueCore.h> #include <gui/BufferQueueProducer.h> -#include <gui/Flags.h> + #include <gui/FrameRateUtils.h> #include <gui/GLConsumer.h> #include <gui/IConsumerListener.h> @@ -1753,7 +1753,7 @@ status_t BufferQueueProducer::setAutoPrerotation(bool autoPrerotation) { return NO_ERROR; } -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) status_t BufferQueueProducer::setFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) { ATRACE_CALL(); diff --git a/libs/gui/FrameRateUtils.cpp b/libs/gui/FrameRateUtils.cpp index 6993bfab45..11524e2b51 100644 --- a/libs/gui/FrameRateUtils.cpp +++ b/libs/gui/FrameRateUtils.cpp @@ -14,14 +14,16 @@ * limitations under the License. */ -#include <gui/Flags.h> #include <gui/FrameRateUtils.h> #include <system/window.h> #include <utils/Log.h> #include <cmath> +#include <com_android_graphics_libgui_flags.h> + namespace android { +using namespace com::android::graphics::libgui; // Returns true if the frameRate is valid. // // @param frameRate the frame rate in Hz @@ -53,7 +55,7 @@ bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrame changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS) { ALOGE("%s failed - invalid change frame rate strategy value %d", functionName, changeFrameRateStrategy); - if (FLAG_BQ_SET_FRAME_RATE) { + if (flags::bq_setframerate()) { return false; } } diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index d0c09e481d..e81c098b85 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -28,7 +28,7 @@ #include <binder/IInterface.h> #include <gui/BufferQueueDefs.h> -#include <gui/Flags.h> + #include <gui/IGraphicBufferProducer.h> #include <gui/IProducerListener.h> #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h> @@ -763,7 +763,7 @@ public: } return result; } -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) virtual status_t setFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) override { Parcel data, reply; @@ -973,7 +973,7 @@ status_t IGraphicBufferProducer::setAutoPrerotation(bool autoPrerotation) { return INVALID_OPERATION; } -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) status_t IGraphicBufferProducer::setFrameRate(float /*frameRate*/, int8_t /*compatibility*/, int8_t /*changeFrameRateStrategy*/) { // No-op for IGBP other than BufferQueue. @@ -1522,7 +1522,7 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) case SET_FRAME_RATE: { CHECK_INTERFACE(IGraphicBuffer, data, reply); float frameRate = data.readFloat(); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index a87f05357f..07a0cfed63 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -43,7 +43,7 @@ #include <gui/AidlStatusUtil.h> #include <gui/BufferItem.h> -#include <gui/Flags.h> + #include <gui/IProducerListener.h> #include <gui/ISurfaceComposer.h> @@ -2571,7 +2571,7 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector<int32_ status_t Surface::setFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) { -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) if (flags::bq_setframerate()) { status_t err = mGraphicBufferProducer->setFrameRate(frameRate, compatibility, changeFrameRateStrategy); diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 02d7c4d2ac..892215ec32 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -19,7 +19,7 @@ #include <gui/BufferItem.h> #include <gui/BufferItemConsumer.h> -#include <gui/Flags.h> + #include <gui/IGraphicBufferProducer.h> #include <gui/SurfaceComposerClient.h> @@ -31,6 +31,8 @@ #include <thread> #include <queue> +#include <com_android_graphics_libgui_flags.h> + namespace android { class BLASTBufferQueue; @@ -59,7 +61,7 @@ public: protected: void onSidebandStreamChanged() override EXCLUDES(mMutex); -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) void onSetFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) override; #endif diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h index 2756277f2c..0948c4d076 100644 --- a/libs/gui/include/gui/BufferQueue.h +++ b/libs/gui/include/gui/BufferQueue.h @@ -19,11 +19,13 @@ #include <gui/BufferItem.h> #include <gui/BufferQueueDefs.h> -#include <gui/Flags.h> + #include <gui/IConsumerListener.h> #include <gui/IGraphicBufferConsumer.h> #include <gui/IGraphicBufferProducer.h> +#include <com_android_graphics_libgui_flags.h> + namespace android { class BufferQueue { @@ -70,7 +72,7 @@ public: void addAndGetFrameTimestamps( const NewFrameEventsEntry* newTimestamps, FrameEventHistoryDelta* outDelta) override; -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) void onSetFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) override; #endif diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index 38805d0221..de47483dca 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -18,7 +18,7 @@ #define ANDROID_GUI_BUFFERQUEUEPRODUCER_H #include <gui/BufferQueueDefs.h> -#include <gui/Flags.h> + #include <gui/IGraphicBufferProducer.h> namespace android { @@ -202,7 +202,7 @@ public: // See IGraphicBufferProducer::setAutoPrerotation virtual status_t setAutoPrerotation(bool autoPrerotation); -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) // See IGraphicBufferProducer::setFrameRate status_t setFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) override; diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h index e183bf2668..51d3959de7 100644 --- a/libs/gui/include/gui/IConsumerListener.h +++ b/libs/gui/include/gui/IConsumerListener.h @@ -19,13 +19,13 @@ #include <binder/IInterface.h> #include <binder/SafeInterface.h> -#include <gui/Flags.h> - #include <utils/Errors.h> #include <utils/RefBase.h> #include <cstdint> +#include <com_android_graphics_libgui_flags.h> + namespace android { class BufferItem; @@ -93,7 +93,7 @@ public: virtual void addAndGetFrameTimestamps(const NewFrameEventsEntry* /*newTimestamps*/, FrameEventHistoryDelta* /*outDelta*/) {} -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) // Notifies the consumer of a setFrameRate call from the producer side. virtual void onSetFrameRate(float /*frameRate*/, int8_t /*compatibility*/, int8_t /*changeFrameRateStrategy*/) {} diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 3562906870..7639e709ca 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -31,7 +31,6 @@ #include <ui/Rect.h> #include <ui/Region.h> -#include <gui/Flags.h> #include <gui/FrameTimestamps.h> #include <gui/HdrMetadata.h> @@ -42,6 +41,8 @@ #include <optional> #include <vector> +#include <com_android_graphics_libgui_flags.h> + namespace android { // ---------------------------------------------------------------------------- @@ -677,7 +678,7 @@ public: // the width and height used for dequeueBuffer will be additionally swapped. virtual status_t setAutoPrerotation(bool autoPrerotation); -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) // Sets the apps intended frame rate. virtual status_t setFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy); diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 38c0eed474..6dcd501404 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -21,7 +21,7 @@ cc_test { "-Wall", "-Werror", "-Wno-extra", - "-DFLAG_BQ_SET_FRAME_RATE=true", + "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_BQ_SETFRAMERATE=true", ], srcs: [ diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 17aa5f1350..1410c7dce0 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -1266,9 +1266,7 @@ TEST_F(BufferQueueTest, TestProducerConnectDisconnect) { } TEST_F(BufferQueueTest, TestBqSetFrameRateFlagBuildTimeIsSet) { - if (flags::bq_setframerate()) { - ASSERT_EQ(true, FLAG_BQ_SET_FRAME_RATE); - } + ASSERT_EQ(flags::bq_setframerate(), COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE)); } struct BufferItemConsumerSetFrameRateListener : public BufferItemConsumer { diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index 116b778608..613a0df040 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -275,10 +275,10 @@ void VelocityTracker::addMovement(nsecs_t eventTime, int32_t pointerId, int32_t } } -void VelocityTracker::addMovement(const MotionEvent* event) { +void VelocityTracker::addMovement(const MotionEvent& event) { // Stores data about which axes to process based on the incoming motion event. std::set<int32_t> axesToProcess; - int32_t actionMasked = event->getActionMasked(); + int32_t actionMasked = event.getActionMasked(); switch (actionMasked) { case AMOTION_EVENT_ACTION_DOWN: @@ -291,7 +291,7 @@ void VelocityTracker::addMovement(const MotionEvent* event) { // Start a new movement trace for a pointer that just went down. // We do this on down instead of on up because the client may want to query the // final velocity for a pointer that just went up. - clearPointer(event->getPointerId(event->getActionIndex())); + clearPointer(event.getPointerId(event.getActionIndex())); axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end()); break; } @@ -300,8 +300,14 @@ void VelocityTracker::addMovement(const MotionEvent* event) { axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end()); break; case AMOTION_EVENT_ACTION_POINTER_UP: + if (event.getFlags() & AMOTION_EVENT_FLAG_CANCELED) { + clearPointer(event.getPointerId(event.getActionIndex())); + return; + } + // Continue to ACTION_UP to ensure that the POINTER_STOPPED logic is triggered. + [[fallthrough]]; case AMOTION_EVENT_ACTION_UP: { - std::chrono::nanoseconds delaySinceLastEvent(event->getEventTime() - mLastEventTime); + std::chrono::nanoseconds delaySinceLastEvent(event.getEventTime() - mLastEventTime); if (delaySinceLastEvent > ASSUME_POINTER_STOPPED_TIME) { ALOGD_IF(DEBUG_VELOCITY, "VelocityTracker: stopped for %s, clearing state upon pointer liftoff.", @@ -325,21 +331,26 @@ void VelocityTracker::addMovement(const MotionEvent* event) { case AMOTION_EVENT_ACTION_SCROLL: axesToProcess.insert(AMOTION_EVENT_AXIS_SCROLL); break; + case AMOTION_EVENT_ACTION_CANCEL: { + clear(); + return; + } + default: // Ignore all other actions. return; } - const size_t historySize = event->getHistorySize(); + const size_t historySize = event.getHistorySize(); for (size_t h = 0; h <= historySize; h++) { - const nsecs_t eventTime = event->getHistoricalEventTime(h); - for (size_t i = 0; i < event->getPointerCount(); i++) { - if (event->isResampled(i, h)) { + const nsecs_t eventTime = event.getHistoricalEventTime(h); + for (size_t i = 0; i < event.getPointerCount(); i++) { + if (event.isResampled(i, h)) { continue; // skip resampled samples } - const int32_t pointerId = event->getPointerId(i); + const int32_t pointerId = event.getPointerId(i); for (int32_t axis : axesToProcess) { - const float position = event->getHistoricalAxisValue(axis, i, h); + const float position = event.getHistoricalAxisValue(axis, i, h); addMovement(eventTime, pointerId, axis, position); } } diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index 978a80f9b3..3672387119 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -48,3 +48,17 @@ flag { description: "Enable additional palm rejection on touchpad while typing" bug: "301055381" } + +flag { + name: "remove_app_switch_drops" + namespace: "input" + description: "Remove the logic of dropping events due to pending app switch" + bug: "284808102" +} + +flag { + name: "disable_reject_touch_on_stylus_hover" + namespace: "input" + description: "Disable touch rejection when the stylus hovers the screen" + bug: "301216095" +} diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs index bbc6d98847..5f05a0f454 100644 --- a/libs/input/rust/input_verifier.rs +++ b/libs/input/rust/input_verifier.rs @@ -118,18 +118,17 @@ impl InputVerifier { match action.into() { MotionAction::Down => { - let it = self - .touching_pointer_ids_by_device - .entry(device_id) - .or_insert_with(HashSet::new); - let pointer_id = pointer_properties[0].id; - if it.contains(&pointer_id) { + if self.touching_pointer_ids_by_device.contains_key(&device_id) { return Err(format!( "{}: Invalid DOWN event - pointers already down for device {:?}: {:?}", - self.name, device_id, it + self.name, device_id, self.touching_pointer_ids_by_device )); } - it.insert(pointer_id); + let it = self + .touching_pointer_ids_by_device + .entry(device_id) + .or_insert_with(HashSet::new); + it.insert(pointer_properties[0].id); } MotionAction::PointerDown { action_index } => { if !self.touching_pointer_ids_by_device.contains_key(&device_id) { @@ -353,6 +352,56 @@ mod tests { } #[test] + fn two_pointer_stream() { + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Touchscreen, + input_bindgen::AMOTION_EVENT_ACTION_DOWN, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + // POINTER 1 DOWN + let two_pointer_properties = + Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Touchscreen, + input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN + | (1 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + &two_pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + // POINTER 0 UP + assert!(verifier + .process_movement( + DeviceId(1), + Source::Touchscreen, + input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP + | (0 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), + &two_pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + // ACTION_UP for pointer id=1 + let pointer_1_properties = Vec::from([RustPointerProperties { id: 1 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Touchscreen, + input_bindgen::AMOTION_EVENT_ACTION_UP, + &pointer_1_properties, + MotionFlags::empty(), + ) + .is_ok()); + } + + #[test] fn multi_device_stream() { let mut verifier = InputVerifier::new("Test", /*should_log*/ false); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index 1c8ec90373..f9ca28083d 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -229,41 +229,23 @@ static std::vector<MotionEvent> createTouchMotionEventStream( return events; } -static std::optional<float> computePlanarVelocity( - const VelocityTracker::Strategy strategy, - const std::vector<PlanarMotionEventEntry>& motions, int32_t axis, - uint32_t pointerId = DEFAULT_POINTER_ID) { +static std::optional<float> computeVelocity(const VelocityTracker::Strategy strategy, + const std::vector<MotionEvent>& events, int32_t axis, + uint32_t pointerId = DEFAULT_POINTER_ID) { VelocityTracker vt(strategy); - std::vector<MotionEvent> events = createTouchMotionEventStream(motions); - for (MotionEvent event : events) { - vt.addMovement(&event); + for (const MotionEvent& event : events) { + vt.addMovement(event); } return vt.getVelocity(axis, pointerId); } -static std::vector<MotionEvent> createMotionEventStream( - int32_t axis, const std::vector<std::pair<std::chrono::nanoseconds, float>>& motion) { - switch (axis) { - case AMOTION_EVENT_AXIS_SCROLL: - return createAxisScrollMotionEventStream(motion); - default: - ADD_FAILURE() << "Axis " << axis << " is not supported"; - return {}; - } -} - -static std::optional<float> computeVelocity( +static std::optional<float> computePlanarVelocity( const VelocityTracker::Strategy strategy, - const std::vector<std::pair<std::chrono::nanoseconds, float>>& motions, int32_t axis) { - VelocityTracker vt(strategy); - - for (const MotionEvent& event : createMotionEventStream(axis, motions)) { - vt.addMovement(&event); - } - - return vt.getVelocity(axis, DEFAULT_POINTER_ID); + const std::vector<PlanarMotionEventEntry>& motions, int32_t axis, uint32_t pointerId) { + std::vector<MotionEvent> events = createTouchMotionEventStream(motions); + return computeVelocity(strategy, events, axis, pointerId); } static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy, @@ -277,23 +259,23 @@ static void computeAndCheckAxisScrollVelocity( const VelocityTracker::Strategy strategy, const std::vector<std::pair<std::chrono::nanoseconds, float>>& motions, std::optional<float> targetVelocity) { - checkVelocity(computeVelocity(strategy, motions, AMOTION_EVENT_AXIS_SCROLL), targetVelocity); + std::vector<MotionEvent> events = createAxisScrollMotionEventStream(motions); + checkVelocity(computeVelocity(strategy, events, AMOTION_EVENT_AXIS_SCROLL), targetVelocity); // The strategy LSQ2 is not compatible with AXIS_SCROLL. In those situations, we should fall // back to a strategy that supports differential axes. - checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, motions, + checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_SCROLL), targetVelocity); } static void computeAndCheckQuadraticVelocity(const std::vector<PlanarMotionEventEntry>& motions, float velocity) { - VelocityTracker vt(VelocityTracker::Strategy::LSQ2); - std::vector<MotionEvent> events = createTouchMotionEventStream(motions); - for (MotionEvent event : events) { - vt.addMovement(&event); - } - std::optional<float> velocityX = vt.getVelocity(AMOTION_EVENT_AXIS_X, 0); - std::optional<float> velocityY = vt.getVelocity(AMOTION_EVENT_AXIS_Y, 0); + std::optional<float> velocityX = + computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, + DEFAULT_POINTER_ID); + std::optional<float> velocityY = + computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, + DEFAULT_POINTER_ID); ASSERT_TRUE(velocityX); ASSERT_TRUE(velocityY); @@ -330,12 +312,14 @@ TEST_F(VelocityTrackerTest, TestDefaultStrategiesForPlanarAxes) { {30ms, {{6, 20}}}, {40ms, {{10, 30}}}}; - EXPECT_EQ(computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X), + EXPECT_EQ(computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, + DEFAULT_POINTER_ID), computePlanarVelocity(VelocityTracker::Strategy::DEFAULT, motions, - AMOTION_EVENT_AXIS_X)); - EXPECT_EQ(computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y), + AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)); + EXPECT_EQ(computePlanarVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, + DEFAULT_POINTER_ID), computePlanarVelocity(VelocityTracker::Strategy::DEFAULT, motions, - AMOTION_EVENT_AXIS_Y)); + AMOTION_EVENT_AXIS_Y, DEFAULT_POINTER_ID)); } TEST_F(VelocityTrackerTest, TestComputedVelocity) { @@ -431,7 +415,7 @@ TEST_F(VelocityTrackerTest, TestGetComputedVelocity) { VelocityTracker vt(VelocityTracker::Strategy::IMPULSE); std::vector<MotionEvent> events = createTouchMotionEventStream(motions); for (const MotionEvent& event : events) { - vt.addMovement(&event); + vt.addMovement(event); } float maxFloat = std::numeric_limits<float>::max(); @@ -509,6 +493,89 @@ TEST_F(VelocityTrackerTest, ThreePointsLinearVelocityTest) { computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 500); } +/** + * When the stream is terminated with ACTION_CANCEL, the resulting velocity should be 0. + */ +TEST_F(VelocityTrackerTest, ActionCancelResultsInZeroVelocity) { + std::vector<PlanarMotionEventEntry> motions = { + {0ms, {{0, 0}}}, // DOWN + {10ms, {{5, 10}}}, // MOVE + {20ms, {{10, 20}}}, // MOVE + {20ms, {{10, 20}}}, // ACTION_UP + }; + std::vector<MotionEvent> events = createTouchMotionEventStream(motions); + // By default, `createTouchMotionEventStream` produces an event stream that terminates with + // ACTION_UP. We need to manually change it to ACTION_CANCEL. + MotionEvent& lastEvent = events.back(); + lastEvent.setAction(AMOTION_EVENT_ACTION_CANCEL); + lastEvent.setFlags(lastEvent.getFlags() | AMOTION_EVENT_FLAG_CANCELED); + const int32_t pointerId = lastEvent.getPointerId(0); + checkVelocity(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_X, + pointerId), + /*targetVelocity*/ std::nullopt); + checkVelocity(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_Y, + pointerId), + /*targetVelocity*/ std::nullopt); + checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_X, + pointerId), + /*targetVelocity*/ std::nullopt); + checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_Y, + pointerId), + /*targetVelocity*/ std::nullopt); +} + +/** + * When the stream is terminated with ACTION_CANCEL, the resulting velocity should be 0. + */ +TEST_F(VelocityTrackerTest, ActionPointerCancelResultsInZeroVelocityForThatPointer) { + std::vector<PlanarMotionEventEntry> motions = { + {0ms, {{0, 5}, {NAN, NAN}}}, // DOWN + {0ms, {{0, 5}, {10, 15}}}, // POINTER_DOWN + {10ms, {{5, 10}, {15, 20}}}, // MOVE + {20ms, {{10, 15}, {20, 25}}}, // MOVE + {30ms, {{10, 15}, {20, 25}}}, // POINTER_UP + {30ms, {{10, 15}, {NAN, NAN}}}, // UP + }; + std::vector<MotionEvent> events = createTouchMotionEventStream(motions); + // Cancel the lifting pointer of the ACTION_POINTER_UP event + MotionEvent& pointerUpEvent = events.rbegin()[1]; + pointerUpEvent.setFlags(pointerUpEvent.getFlags() | AMOTION_EVENT_FLAG_CANCELED); + const int32_t pointerId = pointerUpEvent.getPointerId(pointerUpEvent.getActionIndex()); + // Double check the stream + ASSERT_EQ(1, pointerId); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP, pointerUpEvent.getActionMasked()); + ASSERT_EQ(AMOTION_EVENT_ACTION_UP, events.back().getActionMasked()); + + // Ensure the velocity of the lifting pointer is zero + checkVelocity(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_X, + pointerId), + /*targetVelocity*/ std::nullopt); + checkVelocity(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_Y, + pointerId), + /*targetVelocity*/ std::nullopt); + checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_X, + pointerId), + /*targetVelocity*/ std::nullopt); + checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_Y, + pointerId), + /*targetVelocity*/ std::nullopt); + + // The remaining pointer should have the correct velocity. + const int32_t remainingPointerId = events.back().getPointerId(0); + ASSERT_EQ(0, remainingPointerId); + checkVelocity(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_X, + remainingPointerId), + /*targetVelocity*/ 500); + checkVelocity(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_Y, + remainingPointerId), + /*targetVelocity*/ 500); + checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_X, + remainingPointerId), + /*targetVelocity*/ 500); + checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, events, AMOTION_EVENT_AXIS_Y, + remainingPointerId), + /*targetVelocity*/ 500); +} /** * ================== VelocityTracker tests generated by recording real events ===================== @@ -1336,9 +1403,10 @@ TEST_F(VelocityTrackerTest, TestDefaultStrategyForAxisScroll) { {40ms, 100}, }; - EXPECT_EQ(computeVelocity(VelocityTracker::Strategy::IMPULSE, motions, + std::vector<MotionEvent> events = createAxisScrollMotionEventStream(motions); + EXPECT_EQ(computeVelocity(VelocityTracker::Strategy::IMPULSE, events, AMOTION_EVENT_AXIS_SCROLL), - computeVelocity(VelocityTracker::Strategy::DEFAULT, motions, + computeVelocity(VelocityTracker::Strategy::DEFAULT, events, AMOTION_EVENT_AXIS_SCROLL)); } diff --git a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h index 32fb3508ff..099f47dbe1 100644 --- a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h +++ b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h @@ -19,7 +19,7 @@ #include <android/hardware_buffer.h> #include <gui/BufferQueueDefs.h> #include <gui/ConsumerBase.h> -#include <gui/Flags.h> + #include <gui/IGraphicBufferProducer.h> #include <sys/cdefs.h> #include <system/graphics.h> @@ -352,7 +352,7 @@ protected: /** * onSetFrameRate Notifies the consumer of a setFrameRate call from the producer side. */ -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) void onSetFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) override; #endif diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp index c2535e0bf6..3a09204878 100644 --- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp +++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp @@ -515,7 +515,7 @@ void SurfaceTexture::FrameAvailableListenerProxy::onFrameAvailable(const BufferI } } -#if FLAG_BQ_SET_FRAME_RATE +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE) void SurfaceTexture::onSetFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) { SFT_LOGV("onSetFrameRate: %.2f", frameRate); diff --git a/libs/permission/Android.bp b/libs/permission/Android.bp index 0eeca5469e..86dcaefd87 100644 --- a/libs/permission/Android.bp +++ b/libs/permission/Android.bp @@ -20,6 +20,12 @@ aidl_interface { ], } +filegroup { + name: "framework-permission-aidl-filegroup", + srcs: ["aidl/android/**/*.aidl"], + path: "aidl", +} + cc_library { name: "libpermission", host_supported: true, @@ -35,6 +41,7 @@ cc_library { "-Werror", ], srcs: [ + ":framework-permission-aidl-filegroup", "AppOpsManager.cpp", "IAppOpsCallback.cpp", "IAppOpsService.cpp", diff --git a/libs/permission/AppOpsManager.cpp b/libs/permission/AppOpsManager.cpp index 695927418d..b407d02087 100644 --- a/libs/permission/AppOpsManager.cpp +++ b/libs/permission/AppOpsManager.cpp @@ -31,6 +31,9 @@ namespace android { +using ::android::String16; +using ::android::String8; + static const sp<IBinder>& getClientId() { static pthread_mutex_t gClientIdMutex = PTHREAD_MUTEX_INITIALIZER; static sp<IBinder> gClientId; @@ -43,6 +46,11 @@ static const sp<IBinder>& getClientId() { return gClientId; } + +static std::string getString(const String16& stringToConvert) { + return std::string(String8(stringToConvert).c_str()); +} + AppOpsManager::AppOpsManager() { } @@ -78,9 +86,14 @@ sp<IAppOpsService> AppOpsManager::getService() int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage) { sp<IAppOpsService> service = getService(); - return service != nullptr - ? service->checkOperation(op, uid, callingPackage) - : AppOpsManager::MODE_IGNORED; + if (service == nullptr) { + return AppOpsManager::MODE_IGNORED; + } + AttributionSourceState attributionSourceState; + attributionSourceState.uid = uid; + attributionSourceState.packageName = getString(callingPackage); + + return service->checkOperationWithState(op, attributionSourceState); } int32_t AppOpsManager::checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid, @@ -99,12 +112,18 @@ int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPa int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage, const std::optional<String16>& attributionTag, const String16& message) { sp<IAppOpsService> service = getService(); - int32_t mode = service != nullptr - ? service->noteOperation(op, uid, callingPackage, attributionTag, - shouldCollectNotes(op), message, uid == AID_SYSTEM) - : AppOpsManager::MODE_IGNORED; + if (service == nullptr) { + return AppOpsManager::MODE_IGNORED; + } + AttributionSourceState attributionSourceState; + attributionSourceState.uid = uid; + attributionSourceState.packageName = getString(callingPackage); + if (attributionTag.has_value()) { + attributionSourceState.attributionTag = getString(attributionTag.value()); + } - return mode; + return service->noteOperationWithState(op, attributionSourceState, + shouldCollectNotes(op), message, uid == AID_SYSTEM); } int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage, @@ -117,13 +136,18 @@ int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& c bool startIfModeDefault, const std::optional<String16>& attributionTag, const String16& message) { sp<IAppOpsService> service = getService(); - int32_t mode = service != nullptr - ? service->startOperation(getClientId(), op, uid, callingPackage, - attributionTag, startIfModeDefault, shouldCollectNotes(op), message, - uid == AID_SYSTEM) - : AppOpsManager::MODE_IGNORED; + if (service == nullptr) { + return AppOpsManager::MODE_IGNORED; + } + AttributionSourceState attributionSourceState; + attributionSourceState.uid = uid; + attributionSourceState.packageName = getString(callingPackage); + if (attributionTag.has_value()) { + attributionSourceState.attributionTag = getString(attributionTag.value()); + } - return mode; + return service->startOperationWithState(getClientId(), op, attributionSourceState, + startIfModeDefault,shouldCollectNotes(op), message, uid == AID_SYSTEM); } void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) { @@ -133,9 +157,16 @@ void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPac void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage, const std::optional<String16>& attributionTag) { sp<IAppOpsService> service = getService(); - if (service != nullptr) { - service->finishOperation(getClientId(), op, uid, callingPackage, attributionTag); + if (service == nullptr) { + return; + } + AttributionSourceState attributionSourceState; + attributionSourceState.uid = uid; + attributionSourceState.packageName = getString(callingPackage); + if (attributionTag.has_value()) { + attributionSourceState.attributionTag = getString(attributionTag.value()); } + service->finishOperationWithState(getClientId(), op, attributionSourceState); } void AppOpsManager::startWatchingMode(int32_t op, const String16& packageName, diff --git a/libs/permission/IAppOpsService.cpp b/libs/permission/IAppOpsService.cpp index 7f235a4541..33dd24d728 100644 --- a/libs/permission/IAppOpsService.cpp +++ b/libs/permission/IAppOpsService.cpp @@ -26,6 +26,8 @@ namespace android { +using android::content::AttributionSourceState; + // ---------------------------------------------------------------------- class BpAppOpsService : public BpInterface<IAppOpsService> @@ -36,31 +38,30 @@ public: { } - virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) { + virtual int32_t checkOperationWithState(int32_t code, + const AttributionSourceState &attributionSourceState) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeInt32(code); - data.writeInt32(uid); - data.writeString16(packageName); - remote()->transact(CHECK_OPERATION_TRANSACTION, data, &reply); + data.writeParcelable(attributionSourceState); + remote()->transact(CHECK_OPERATION_WITH_STATE_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return MODE_ERRORED; return reply.readInt32(); } - virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName, - const std::optional<String16>& attributionTag, bool shouldCollectAsyncNotedOp, - const String16& message, bool shouldCollectMessage) { + virtual int32_t noteOperationWithState(int32_t code, + const AttributionSourceState& attributionSourceState, + bool shouldCollectAsyncNotedOp, const String16& message, + bool shouldCollectMessage) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeInt32(code); - data.writeInt32(uid); - data.writeString16(packageName); - data.writeString16(attributionTag); + data.writeParcelable(attributionSourceState); data.writeBool(shouldCollectAsyncNotedOp); data.writeString16(message); data.writeBool(shouldCollectMessage); - remote()->transact(NOTE_OPERATION_TRANSACTION, data, &reply); + remote()->transact(NOTE_OPERATION_WITH_STATE_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return MODE_ERRORED; // TODO b/184855056: extract to class @@ -69,22 +70,20 @@ public: return reply.readInt32(); } - virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid, - const String16& packageName, const std::optional<String16>& attributionTag, - bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message, + virtual int32_t startOperationWithState(const sp<IBinder>& token, int32_t code, + const AttributionSourceState& attributionSourceState, bool startIfModeDefault, + bool shouldCollectAsyncNotedOp, const String16& message, bool shouldCollectMessage) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeStrongBinder(token); data.writeInt32(code); - data.writeInt32(uid); - data.writeString16(packageName); - data.writeString16(attributionTag); + data.writeParcelable(attributionSourceState); data.writeBool(startIfModeDefault); data.writeBool(shouldCollectAsyncNotedOp); data.writeString16(message); data.writeBool(shouldCollectMessage); - remote()->transact(START_OPERATION_TRANSACTION, data, &reply); + remote()->transact(START_OPERATION_WITH_STATE_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return MODE_ERRORED; // TODO b/184855056: extract to class @@ -93,16 +92,14 @@ public: return reply.readInt32(); } - virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid, - const String16& packageName, const std::optional<String16>& attributionTag) { + virtual void finishOperationWithState(const sp<IBinder>& token, int32_t code, + const AttributionSourceState& attributionSourceState) { Parcel data, reply; data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor()); data.writeStrongBinder(token); data.writeInt32(code); - data.writeInt32(uid); - data.writeString16(packageName); - data.writeString16(attributionTag); - remote()->transact(FINISH_OPERATION_TRANSACTION, data, &reply); + data.writeParcelable(attributionSourceState); + remote()->transact(FINISH_OPERATION_WITH_STATE_TRANSACTION, data, &reply); } virtual void startWatchingMode(int32_t op, const String16& packageName, @@ -189,59 +186,65 @@ status_t BnAppOpsService::onTransact( { //printf("AppOpsService received: "); data.print(); switch(code) { - case CHECK_OPERATION_TRANSACTION: { + case CHECK_OPERATION_WITH_STATE_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); int32_t code = data.readInt32(); - int32_t uid = data.readInt32(); - String16 packageName = data.readString16(); - int32_t res = checkOperation(code, uid, packageName); + AttributionSourceState attributionSourceState; + status_t status = data.readParcelable(&attributionSourceState); + if (status != NO_ERROR) { + return status; + } + int32_t res = checkOperationWithState(code, attributionSourceState); reply->writeNoException(); reply->writeInt32(res); return NO_ERROR; } break; - case NOTE_OPERATION_TRANSACTION: { + case NOTE_OPERATION_WITH_STATE_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); int32_t code = data.readInt32(); - int32_t uid = data.readInt32(); - String16 packageName = data.readString16(); - std::optional<String16> attributionTag; - data.readString16(&attributionTag); + AttributionSourceState attributionSourceState; + status_t status = data.readParcelable(&attributionSourceState); + if (status != NO_ERROR) { + return status; + } bool shouldCollectAsyncNotedOp = data.readBool(); String16 message = data.readString16(); bool shouldCollectMessage = data.readBool(); - int32_t res = noteOperation(code, uid, packageName, attributionTag, + int32_t res = noteOperationWithState(code, attributionSourceState, shouldCollectAsyncNotedOp, message, shouldCollectMessage); reply->writeNoException(); reply->writeInt32(res); return NO_ERROR; } break; - case START_OPERATION_TRANSACTION: { + case START_OPERATION_WITH_STATE_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); sp<IBinder> token = data.readStrongBinder(); int32_t code = data.readInt32(); - int32_t uid = data.readInt32(); - String16 packageName = data.readString16(); - std::optional<String16> attributionTag; - data.readString16(&attributionTag); + AttributionSourceState attributionSourceState; + status_t status = data.readParcelable(&attributionSourceState); + if (status != NO_ERROR) { + return status; + } bool startIfModeDefault = data.readBool(); bool shouldCollectAsyncNotedOp = data.readBool(); String16 message = data.readString16(); bool shouldCollectMessage = data.readBool(); - int32_t res = startOperation(token, code, uid, packageName, attributionTag, + int32_t res = startOperationWithState(token, code, attributionSourceState, startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage); reply->writeNoException(); reply->writeInt32(res); return NO_ERROR; } break; - case FINISH_OPERATION_TRANSACTION: { + case FINISH_OPERATION_WITH_STATE_TRANSACTION: { CHECK_INTERFACE(IAppOpsService, data, reply); sp<IBinder> token = data.readStrongBinder(); int32_t code = data.readInt32(); - int32_t uid = data.readInt32(); - String16 packageName = data.readString16(); - std::optional<String16> attributionTag; - data.readString16(&attributionTag); - finishOperation(token, code, uid, packageName, attributionTag); + AttributionSourceState attributionSourceState; + status_t status = data.readParcelable(&attributionSourceState); + if (status != NO_ERROR) { + return status; + } + finishOperationWithState(token, code, attributionSourceState); reply->writeNoException(); return NO_ERROR; } break; diff --git a/libs/permission/include/binder/IAppOpsService.h b/libs/permission/include/binder/IAppOpsService.h index 918fcdbce1..a5fdc54f28 100644 --- a/libs/permission/include/binder/IAppOpsService.h +++ b/libs/permission/include/binder/IAppOpsService.h @@ -16,6 +16,7 @@ #pragma once +#include <android/content/AttributionSourceState.h> #include <binder/IAppOpsCallback.h> #include <binder/IInterface.h> @@ -27,23 +28,24 @@ namespace android { +using android::content::AttributionSourceState; + // ---------------------------------------------------------------------- class IAppOpsService : public IInterface { public: DECLARE_META_INTERFACE(AppOpsService) - - virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0; - virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName, - const std::optional<String16>& attributionTag, bool shouldCollectAsyncNotedOp, + virtual int32_t checkOperationWithState(int32_t code, + const AttributionSourceState& attributionSourceState) = 0; + virtual int32_t noteOperationWithState(int32_t code, + const AttributionSourceState& attributionSourceState, bool shouldCollectAsyncNotedOp, const String16& message, bool shouldCollectMessage) = 0; - virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid, - const String16& packageName, const std::optional<String16>& attributionTag, - bool startIfModeDefault, bool shouldCollectAsyncNotedOp, const String16& message, - bool shouldCollectMessage) = 0; - virtual void finishOperation(const sp<IBinder>& token, int32_t code, int32_t uid, - const String16& packageName, const std::optional<String16>& attributionTag) = 0; + virtual int32_t startOperationWithState(const sp<IBinder>& token, int32_t code, + const AttributionSourceState& attributionSourceState, bool startIfModeDefault, + bool shouldCollectAsyncNotedOp, const String16& message, bool shouldCollectMessage) = 0; + virtual void finishOperationWithState(const sp<IBinder>& token, int32_t code, + const AttributionSourceState& attributionSourceState) = 0; virtual void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback) = 0; virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0; @@ -56,10 +58,10 @@ public: int32_t flags, const sp<IAppOpsCallback>& callback) = 0; enum { - CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, - NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1, - START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2, - FINISH_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+3, + CHECK_OPERATION_WITH_STATE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+50, + NOTE_OPERATION_WITH_STATE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+52, + START_OPERATION_WITH_STATE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+53, + FINISH_OPERATION_WITH_STATE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+54, START_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+4, STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5, PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6, diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 7b2f39cd9c..04e2fffaef 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -567,7 +567,6 @@ Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) { return nullptr; } - // use ANGLE APK driver android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE); driver_t* hnd = nullptr; @@ -636,13 +635,7 @@ Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact) { ATRACE_CALL(); - if (strcmp(suffix, "angle") == 0) { - // use system ANGLE driver - android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE); - } else { - android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL); - } - + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL); driver_t* hnd = nullptr; void* dso = load_system_driver("GLES", suffix, exact); if (dso) { diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index d447d1e91a..f06a0457d3 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -163,11 +163,11 @@ void GpuStats::insertDriverStats(const std::string& driverPackageName, addLoadingTime(driver, driverLoadingTime, &appInfo); appInfo.appPackageName = appPackageName; appInfo.driverVersionCode = driverVersionCode; - appInfo.angleInUse = driver == GpuStatsInfo::Driver::ANGLE; + appInfo.angleInUse = driverPackageName == "angle"; appInfo.lastAccessTime = std::chrono::system_clock::now(); mAppStats.insert({appStatsKey, appInfo}); } else { - mAppStats[appStatsKey].angleInUse = driver == GpuStatsInfo::Driver::ANGLE; + mAppStats[appStatsKey].angleInUse = driverPackageName == "angle"; addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]); mAppStats[appStatsKey].lastAccessTime = std::chrono::system_clock::now(); } diff --git a/services/inputflinger/PreferStylusOverTouchBlocker.cpp b/services/inputflinger/PreferStylusOverTouchBlocker.cpp index ee0ab33559..d9d0450148 100644 --- a/services/inputflinger/PreferStylusOverTouchBlocker.cpp +++ b/services/inputflinger/PreferStylusOverTouchBlocker.cpp @@ -15,10 +15,15 @@ */ #include "PreferStylusOverTouchBlocker.h" +#include <com_android_input_flags.h> #include <input/PrintTools.h> +namespace input_flags = com::android::input::flags; + namespace android { +const bool BLOCK_TOUCH_WHEN_STYLUS_HOVER = !input_flags::disable_reject_touch_on_stylus_hover(); + static std::pair<bool, bool> checkToolType(const NotifyMotionArgs& args) { bool hasStylus = false; bool hasTouch = false; @@ -96,8 +101,11 @@ static void intersectInPlace(std::map<K, V>& map, const std::set<K>& set2) { std::vector<NotifyMotionArgs> PreferStylusOverTouchBlocker::processMotion( const NotifyMotionArgs& args) { const auto [hasTouch, hasStylus] = checkToolType(args); - const bool isUpOrCancel = - args.action == AMOTION_EVENT_ACTION_UP || args.action == AMOTION_EVENT_ACTION_CANCEL; + const bool isDisengageOrCancel = BLOCK_TOUCH_WHEN_STYLUS_HOVER + ? (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT || + args.action == AMOTION_EVENT_ACTION_UP || args.action == AMOTION_EVENT_ACTION_CANCEL) + : (args.action == AMOTION_EVENT_ACTION_UP || + args.action == AMOTION_EVENT_ACTION_CANCEL); if (hasTouch && hasStylus) { mDevicesWithMixedToolType.insert(args.deviceId); @@ -109,7 +117,7 @@ std::vector<NotifyMotionArgs> PreferStylusOverTouchBlocker::processMotion( if (mCanceledDevices.find(args.deviceId) != mCanceledDevices.end()) { // If we started to cancel events from this device, continue to do so to keep // the stream consistent. It should happen at most once per "mixed" device. - if (isUpOrCancel) { + if (isDisengageOrCancel) { mCanceledDevices.erase(args.deviceId); mLastTouchEvents.erase(args.deviceId); } @@ -119,10 +127,13 @@ std::vector<NotifyMotionArgs> PreferStylusOverTouchBlocker::processMotion( } const bool isStylusEvent = hasStylus; - const bool isDown = args.action == AMOTION_EVENT_ACTION_DOWN; + const bool isEngage = BLOCK_TOUCH_WHEN_STYLUS_HOVER + ? (args.action == AMOTION_EVENT_ACTION_DOWN || + args.action == AMOTION_EVENT_ACTION_HOVER_ENTER) + : (args.action == AMOTION_EVENT_ACTION_DOWN); if (isStylusEvent) { - if (isDown) { + if (isEngage) { // Reject all touch while stylus is down mActiveStyli.insert(args.deviceId); @@ -143,7 +154,7 @@ std::vector<NotifyMotionArgs> PreferStylusOverTouchBlocker::processMotion( result.push_back(args); return result; } - if (isUpOrCancel) { + if (isDisengageOrCancel) { mActiveStyli.erase(args.deviceId); } // Never drop stylus events @@ -158,7 +169,7 @@ std::vector<NotifyMotionArgs> PreferStylusOverTouchBlocker::processMotion( } const bool shouldDrop = mCanceledDevices.find(args.deviceId) != mCanceledDevices.end(); - if (isUpOrCancel) { + if (isDisengageOrCancel) { mCanceledDevices.erase(args.deviceId); mLastTouchEvents.erase(args.deviceId); } @@ -169,7 +180,7 @@ std::vector<NotifyMotionArgs> PreferStylusOverTouchBlocker::processMotion( return {}; } - if (!isUpOrCancel) { + if (!isDisengageOrCancel) { mLastTouchEvents[args.deviceId] = args; } return {args}; diff --git a/services/inputflinger/dispatcher/DebugConfig.h b/services/inputflinger/dispatcher/DebugConfig.h index c7d98ab31a..c889b9b136 100644 --- a/services/inputflinger/dispatcher/DebugConfig.h +++ b/services/inputflinger/dispatcher/DebugConfig.h @@ -69,6 +69,16 @@ const bool DEBUG_INJECTION = android::base::ShouldLog(android::base::LogSeverity::DEBUG, LOG_TAG "Injection"); /** + * Generally, we always log whenever events are dropped. However, to reduce logspam, some messages + * are suppressed. + * Log additional debug messages about dropped input events with this flag. + * Enable this via "adb shell setprop log.tag.InputDispatcherDroppedEventsVerbose DEBUG". + * Requires system_server restart via `adb shell stop && adb shell start`. + */ +const bool DEBUG_DROPPED_EVENTS_VERBOSE = + android::base::ShouldLog(android::base::LogSeverity::DEBUG, LOG_TAG "DroppedEventsVerbose"); + +/** * Log debug messages about input focus tracking. * Enable this via "adb shell setprop log.tag.InputDispatcherFocus DEBUG" (requires restart) */ diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 7dfbf94883..47b9a0c62f 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -756,10 +756,6 @@ bool shouldSplitTouch(const TouchState& touchState, const MotionEntry& entry) { // --- InputDispatcher --- InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy) - : InputDispatcher(policy, STALE_EVENT_TIMEOUT) {} - -InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy, - std::chrono::nanoseconds staleEventTimeout) : mPolicy(policy), mPendingEvent(nullptr), mLastDropReason(DropReason::NOT_DROPPED), @@ -774,7 +770,6 @@ InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy, mMaximumObscuringOpacityForTouch(1.0f), mFocusedDisplayId(ADISPLAY_ID_DEFAULT), mWindowTokenWithPointerCapture(nullptr), - mStaleEventTimeout(staleEventTimeout), mLatencyAggregator(), mLatencyTracker(&mLatencyAggregator) { mLooper = sp<Looper>::make(false); @@ -956,20 +951,25 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { // Optimize latency of app switches. // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has // been pressed. When it expires, we preempt dispatch and drop all other pending events. - bool isAppSwitchDue = mAppSwitchDueTime <= currentTime; - if (mAppSwitchDueTime < *nextWakeupTime) { - *nextWakeupTime = mAppSwitchDueTime; + bool isAppSwitchDue; + if (!input_flags::remove_app_switch_drops()) { + isAppSwitchDue = mAppSwitchDueTime <= currentTime; + if (mAppSwitchDueTime < *nextWakeupTime) { + *nextWakeupTime = mAppSwitchDueTime; + } } // Ready to start a new event. // If we don't already have a pending event, go grab one. if (!mPendingEvent) { if (mInboundQueue.empty()) { - if (isAppSwitchDue) { - // The inbound queue is empty so the app switch key we were waiting - // for will never arrive. Stop waiting for it. - resetPendingAppSwitchLocked(false); - isAppSwitchDue = false; + if (!input_flags::remove_app_switch_drops()) { + if (isAppSwitchDue) { + // The inbound queue is empty so the app switch key we were waiting + // for will never arrive. Stop waiting for it. + resetPendingAppSwitchLocked(false); + isAppSwitchDue = false; + } } // Synthesize a key repeat if appropriate. @@ -1067,12 +1067,14 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { case EventEntry::Type::KEY: { std::shared_ptr<KeyEntry> keyEntry = std::static_pointer_cast<KeyEntry>(mPendingEvent); - if (isAppSwitchDue) { - if (isAppSwitchKeyEvent(*keyEntry)) { - resetPendingAppSwitchLocked(true); - isAppSwitchDue = false; - } else if (dropReason == DropReason::NOT_DROPPED) { - dropReason = DropReason::APP_SWITCH; + if (!input_flags::remove_app_switch_drops()) { + if (isAppSwitchDue) { + if (isAppSwitchKeyEvent(*keyEntry)) { + resetPendingAppSwitchLocked(true); + isAppSwitchDue = false; + } else if (dropReason == DropReason::NOT_DROPPED) { + dropReason = DropReason::APP_SWITCH; + } } } if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *keyEntry)) { @@ -1088,8 +1090,10 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { case EventEntry::Type::MOTION: { std::shared_ptr<MotionEntry> motionEntry = std::static_pointer_cast<MotionEntry>(mPendingEvent); - if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) { - dropReason = DropReason::APP_SWITCH; + if (!input_flags::remove_app_switch_drops()) { + if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) { + dropReason = DropReason::APP_SWITCH; + } } if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) { dropReason = DropReason::STALE; @@ -1104,8 +1108,10 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { case EventEntry::Type::SENSOR: { std::shared_ptr<SensorEntry> sensorEntry = std::static_pointer_cast<SensorEntry>(mPendingEvent); - if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) { - dropReason = DropReason::APP_SWITCH; + if (!input_flags::remove_app_switch_drops()) { + if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) { + dropReason = DropReason::APP_SWITCH; + } } // Sensor timestamps use SYSTEM_TIME_BOOTTIME time base, so we can't use // 'currentTime' here, get SYSTEM_TIME_BOOTTIME instead. @@ -1131,7 +1137,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { } bool InputDispatcher::isStaleEvent(nsecs_t currentTime, const EventEntry& entry) { - return std::chrono::nanoseconds(currentTime - entry.eventTime) >= mStaleEventTimeout; + return mPolicy.isStaleEvent(currentTime, entry.eventTime); } /** @@ -1207,21 +1213,23 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE // If the application takes too long to catch up then we drop all events preceding // the app switch key. const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry); - if (isAppSwitchKeyEvent(keyEntry)) { - if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) { - mAppSwitchSawKeyDown = true; - } else if (keyEntry.action == AKEY_EVENT_ACTION_UP) { - if (mAppSwitchSawKeyDown) { - if (DEBUG_APP_SWITCH) { - ALOGD("App switch is pending!"); + + if (!input_flags::remove_app_switch_drops()) { + if (isAppSwitchKeyEvent(keyEntry)) { + if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) { + mAppSwitchSawKeyDown = true; + } else if (keyEntry.action == AKEY_EVENT_ACTION_UP) { + if (mAppSwitchSawKeyDown) { + if (DEBUG_APP_SWITCH) { + ALOGD("App switch is pending!"); + } + mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT; + mAppSwitchSawKeyDown = false; + needWake = true; } - mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT; - mAppSwitchSawKeyDown = false; - needWake = true; } } } - // If a new up event comes in, and the pending event with same key code has been asked // to try again later because of the policy. We have to reset the intercept key wake up // time for it may have been handled in the policy and could be dropped. @@ -2032,10 +2040,10 @@ void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, if (connection != nullptr) { prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget); } else { - if (DEBUG_FOCUS) { - ALOGD("Dropping event delivery to target with channel '%s' because it " - "is no longer registered with the input dispatcher.", - inputTarget.inputChannel->getName().c_str()); + if (DEBUG_DROPPED_EVENTS_VERBOSE) { + LOG(INFO) << "Dropping event delivery to target with channel " + << inputTarget.inputChannel->getName() + << " because it is no longer registered with the input dispatcher."; } } } @@ -2453,10 +2461,11 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( // If the pointer is not currently down, then ignore the event. if (!tempTouchState.isDown(entry.deviceId) && maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) { - LOG(INFO) << "Dropping event because the pointer for device " << entry.deviceId - << " is not down or we previously " - "dropped the pointer down event in display " - << displayId << ": " << entry.getDescription(); + if (DEBUG_DROPPED_EVENTS_VERBOSE) { + LOG(INFO) << "Dropping event because the pointer for device " << entry.deviceId + << " is not down or we previously dropped the pointer down event in " + << "display " << displayId << ": " << entry.getDescription(); + } outInjectionResult = InputEventInjectionResult::FAILED; return {}; } @@ -2864,8 +2873,13 @@ void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHa it = inputTargets.end() - 1; } - LOG_ALWAYS_FATAL_IF(it->flags != targetFlags); - LOG_ALWAYS_FATAL_IF(it->globalScaleFactor != windowInfo->globalScaleFactor); + if (it->flags != targetFlags) { + LOG(ERROR) << "Flags don't match! targetFlags=" << targetFlags.string() << ", it=" << *it; + } + if (it->globalScaleFactor != windowInfo->globalScaleFactor) { + LOG(ERROR) << "Mismatch! it->globalScaleFactor=" << it->globalScaleFactor + << ", windowInfo->globalScaleFactor=" << windowInfo->globalScaleFactor; + } } void InputDispatcher::addPointerWindowTargetLocked( @@ -2910,8 +2924,13 @@ void InputDispatcher::addPointerWindowTargetLocked( it = inputTargets.end() - 1; } - LOG_ALWAYS_FATAL_IF(it->flags != targetFlags); - LOG_ALWAYS_FATAL_IF(it->globalScaleFactor != windowInfo->globalScaleFactor); + if (it->flags != targetFlags) { + LOG(ERROR) << "Flags don't match! targetFlags=" << targetFlags.string() << ", it=" << *it; + } + if (it->globalScaleFactor != windowInfo->globalScaleFactor) { + LOG(ERROR) << "Mismatch! it->globalScaleFactor=" << it->globalScaleFactor + << ", windowInfo->globalScaleFactor=" << windowInfo->globalScaleFactor; + } it->addPointers(pointerIds, windowInfo->transform); } @@ -4419,7 +4438,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) { const auto touchStateIt = mTouchStatesByDisplay.find(args.displayId); if (touchStateIt != mTouchStatesByDisplay.end()) { const TouchState& touchState = touchStateIt->second; - if (touchState.hasTouchingPointers(args.deviceId)) { + if (touchState.hasTouchingPointers(args.deviceId) || + touchState.hasHoveringPointers(args.deviceId)) { policyFlags |= POLICY_FLAG_PASS_TO_USER; } } @@ -4531,6 +4551,7 @@ void InputDispatcher::notifySwitch(const NotifySwitchArgs& args) { } void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs& args) { + // TODO(b/308677868) Remove device reset from the InputListener interface if (debugInboundEventDetails()) { ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args.eventTime, args.deviceId); @@ -4672,6 +4693,30 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev } mLock.lock(); + + if (policyFlags & POLICY_FLAG_FILTERED) { + // The events from InputFilter impersonate real hardware devices. Check these + // events for consistency and print an error. An inconsistent event sent from + // InputFilter could cause a crash in the later stages of dispatching pipeline. + auto [it, _] = + mInputFilterVerifiersByDisplay + .try_emplace(displayId, + StringPrintf("Injection on %" PRId32, displayId)); + InputVerifier& verifier = it->second; + + Result<void> result = + verifier.processMovement(resolvedDeviceId, motionEvent.getSource(), + motionEvent.getAction(), + motionEvent.getPointerCount(), + motionEvent.getPointerProperties(), + motionEvent.getSamplePointerCoords(), flags); + if (!result.ok()) { + logDispatchStateLocked(); + LOG(ERROR) << "Inconsistent event: " << motionEvent + << ", reason: " << result.error(); + } + } + const nsecs_t* sampleEventTimes = motionEvent.getSampleEventTimes(); const size_t pointerCount = motionEvent.getPointerCount(); const std::vector<PointerProperties> @@ -5797,6 +5842,9 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) const { dump += INDENT "Connections: <none>\n"; } + dump += "input_flags::remove_app_switch_drops() = "; + dump += toString(input_flags::remove_app_switch_drops()); + dump += "\n"; if (isAppSwitchPendingLocked()) { dump += StringPrintf(INDENT "AppSwitch: pending, due in %" PRId64 "ms\n", ns2ms(mAppSwitchDueTime - now())); @@ -6733,6 +6781,7 @@ void InputDispatcher::displayRemoved(int32_t displayId) { // Remove the associated touch mode state. mTouchModePerDisplay.erase(displayId); mVerifiersByDisplay.erase(displayId); + mInputFilterVerifiersByDisplay.erase(displayId); } // release lock // Wake up poll loop since it may need to make new input dispatching choices. diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index a1127a0f45..e428c4e915 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -82,8 +82,6 @@ public: static constexpr bool kDefaultInTouchMode = true; explicit InputDispatcher(InputDispatcherPolicyInterface& policy); - explicit InputDispatcher(InputDispatcherPolicyInterface& policy, - std::chrono::nanoseconds staleEventTimeout); ~InputDispatcher() override; void dump(std::string& dump) const override; @@ -288,7 +286,8 @@ private: void transformMotionEntryForInjectionLocked(MotionEntry&, const ui::Transform& injectedTransform) const REQUIRES(mLock); - + // Per-display correction of injected events + std::map</*displayId*/ int32_t, InputVerifier> mInputFilterVerifiersByDisplay GUARDED_BY(mLock); std::condition_variable mInjectionSyncFinished; void incrementPendingForegroundDispatches(EventEntry& entry); void decrementPendingForegroundDispatches(EventEntry& entry); @@ -461,9 +460,6 @@ private: */ std::optional<nsecs_t> mNoFocusedWindowTimeoutTime GUARDED_BY(mLock); - // Amount of time to allow for an event to be dispatched (measured since its eventTime) - // before considering it stale and dropping it. - const std::chrono::nanoseconds mStaleEventTimeout; bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry); bool shouldPruneInboundQueueLocked(const MotionEntry& motionEntry) REQUIRES(mLock); diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h index af28e48121..bf4880480c 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h @@ -18,6 +18,7 @@ #include "InputDispatcherConfiguration.h" +#include <android-base/properties.h> #include <binder/IBinder.h> #include <gui/InputApplication.h> #include <input/Input.h> @@ -118,6 +119,16 @@ public: /* Poke user activity for an event dispatched to a window. */ virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType, int32_t displayId) = 0; + /* + * Return true if the provided event is stale, and false otherwise. Used for determining + * whether the dispatcher should drop the event. + */ + virtual bool isStaleEvent(nsecs_t currentTime, nsecs_t eventTime) { + static const std::chrono::duration STALE_EVENT_TIMEOUT = + std::chrono::seconds(10) * android::base::HwTimeoutMultiplier(); + return std::chrono::nanoseconds(currentTime - eventTime) >= STALE_EVENT_TIMEOUT; + } + /* Notifies the policy that a pointer down event has occurred outside the current focused * window. * diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 3c87f7194d..2509c60573 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -112,8 +112,6 @@ static constexpr gui::Uid SECONDARY_WINDOW_UID{1012}; // An arbitrary pid of the gesture monitor window static constexpr gui::Pid MONITOR_PID{2001}; -static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms; - /** * If we expect to receive the event, the timeout can be made very long. When the test are running * correctly, we will actually never wait until the end of the timeout because the wait will end @@ -348,6 +346,8 @@ public: mInterceptKeyTimeout = timeout; } + void setStaleEventTimeout(std::chrono::nanoseconds timeout) { mStaleEventTimeout = timeout; } + void assertUserActivityPoked() { std::scoped_lock lock(mLock); ASSERT_TRUE(mPokedUserActivity) << "Expected user activity to have been poked"; @@ -391,6 +391,8 @@ private: std::chrono::milliseconds mInterceptKeyTimeout = 0ms; + std::chrono::nanoseconds mStaleEventTimeout = 1000ms; + BlockingQueue<std::pair<int32_t /*deviceId*/, std::set<gui::Uid>>> mNotifiedInteractions; // All three ANR-related callbacks behave the same way, so we use this generic function to wait @@ -545,6 +547,10 @@ private: mPokedUserActivity = true; } + bool isStaleEvent(nsecs_t currentTime, nsecs_t eventTime) override { + return std::chrono::nanoseconds(currentTime - eventTime) >= mStaleEventTimeout; + } + void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override { std::scoped_lock lock(mLock); mOnPointerDownToken = newToken; @@ -586,7 +592,8 @@ protected: void SetUp() override { mFakePolicy = std::make_unique<FakeInputDispatcherPolicy>(); - mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy, STALE_EVENT_TIMEOUT); + mDispatcher = std::make_unique<InputDispatcher>(*mFakePolicy); + mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false); // Start InputDispatcher thread ASSERT_EQ(OK, mDispatcher->start()); @@ -2160,6 +2167,69 @@ TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) { } /** + * Same as the above 'TwoPointerCancelInconsistentPolicy' test, but for hovers. + * The policy typically sets POLICY_FLAG_PASS_TO_USER to the events. But when the display is not + * interactive, it might stop sending this flag. + * We've already ensured the consistency of the touch event in this case, and we should also ensure + * the consistency of the hover event in this case. + * + * Test procedure: + * HOVER_ENTER -> HOVER_MOVE -> (stop sending POLICY_FLAG_PASS_TO_USER) -> HOVER_EXIT + * HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT + * + * We expect to receive two full streams of hover events. + */ +TEST_F(InputDispatcherTest, HoverEventInconsistentPolicy) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + + sp<FakeWindowHandle> window = + sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 300, 300)); + + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE)); + + // Send hover exit without the default policy flags. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) + .policyFlags(0) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102)) + .build()); + + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); + + // Send a simple hover event stream, ensure dispatcher not crashed and window can receive + // right event. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(200).y(201)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE)); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(201).y(202)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); +} + +/** * Two windows: a window on the left and a window on the right. * Mouse is hovered from the right window into the left window. * Next, we tap on the left window, where the cursor was last seen. @@ -7529,6 +7599,8 @@ TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) { mWindow->consumeFocusEvent(false); KeyEvent event; + static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms; + mFakePolicy->setStaleEventTimeout(STALE_EVENT_TIMEOUT); const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC) - std::chrono::nanoseconds(STALE_EVENT_TIMEOUT).count(); diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h index 1775a7a4a6..f32fb3a5c7 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayMode.h +++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h @@ -30,8 +30,8 @@ #include <scheduler/Fps.h> #include "DisplayHardware/Hal.h" +#include "FlagManager.h" #include "Scheduler/StrongTyping.h" -#include "Utils/FlagUtils.h" namespace android { @@ -50,7 +50,6 @@ using DisplayModeId = StrongTyping<ui::DisplayModeId, struct DisplayModeIdTag, C using DisplayModes = ftl::SmallMap<DisplayModeId, DisplayModePtr, 3>; using DisplayModeIterator = DisplayModes::const_iterator; -using namespace com::android::graphics::surfaceflinger; class DisplayMode { public: @@ -140,7 +139,7 @@ public: // Peak refresh rate represents the highest refresh rate that can be used // for the presentation. Fps getPeakFps() const { - return flagutils::vrrConfigEnabled() && mVrrConfig + return FlagManager::getInstance().vrr_config() && mVrrConfig ? Fps::fromPeriodNsecs(mVrrConfig->minFrameIntervalNs) : mVsyncRate; } diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp index f8ad8f6941..11a5e0da8c 100644 --- a/services/surfaceflinger/FlagManager.cpp +++ b/services/surfaceflinger/FlagManager.cpp @@ -26,37 +26,21 @@ #include <server_configurable_flags/get_flags.h> #include <cinttypes> +#include <com_android_graphics_surfaceflinger_flags.h> + namespace android { +using namespace com::android::graphics::surfaceflinger; + static constexpr const char* kExperimentNamespace = "surface_flinger_native_boot"; -static constexpr const int64_t kDemoFlag = -1; -FlagManager::~FlagManager() = default; +std::unique_ptr<FlagManager> FlagManager::mInstance; +std::once_flag FlagManager::mOnce; -void FlagManager::dump(std::string& result) const { - base::StringAppendF(&result, "FlagManager values: \n"); - base::StringAppendF(&result, "demo_flag: %" PRId64 "\n", demo_flag()); - base::StringAppendF(&result, "use_adpf_cpu_hint: %s\n", use_adpf_cpu_hint() ? "true" : "false"); - base::StringAppendF(&result, "use_skia_tracing: %s\n", use_skia_tracing() ? "true" : "false"); -} +FlagManager::FlagManager(ConstructorTag) {} +FlagManager::~FlagManager() = default; namespace { -template <typename T> -std::optional<T> doParse(const char* str); - -template <> -[[maybe_unused]] std::optional<int32_t> doParse(const char* str) { - int32_t ret; - return base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt; -} - -template <> -[[maybe_unused]] std::optional<int64_t> doParse(const char* str) { - int64_t ret; - return base::ParseInt(str, &ret) ? std::make_optional(ret) : std::nullopt; -} - -template <> -[[maybe_unused]] std::optional<bool> doParse(const char* str) { +std::optional<bool> parseBool(const char* str) { base::ParseBoolResult parseResult = base::ParseBool(str); switch (parseResult) { case base::ParseBoolResult::kTrue: @@ -67,44 +51,133 @@ template <> return std::nullopt; } } + +bool getFlagValue(std::function<bool()> getter, std::optional<bool> overrideValue) { + if (overrideValue.has_value()) { + return *overrideValue; + } + + return getter(); +} + +void dumpFlag(std::string& result, const char* name, std::function<bool()> getter) { + base::StringAppendF(&result, "%s: %s\n", name, getter() ? "true" : "false"); +} + } // namespace -std::string FlagManager::getServerConfigurableFlag(const std::string& experimentFlagName) const { - return server_configurable_flags::GetServerConfigurableFlag(kExperimentNamespace, - experimentFlagName, ""); +const FlagManager& FlagManager::getInstance() { + return getMutableInstance(); } -template int32_t FlagManager::getValue<int32_t>(const std::string&, std::optional<int32_t>, - int32_t) const; -template int64_t FlagManager::getValue<int64_t>(const std::string&, std::optional<int64_t>, - int64_t) const; -template bool FlagManager::getValue<bool>(const std::string&, std::optional<bool>, bool) const; -template <typename T> -T FlagManager::getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt, - T defaultValue) const { - // System property takes precedence over the experiment config server value. - if (systemPropertyOpt.has_value()) { - return *systemPropertyOpt; - } - std::string str = getServerConfigurableFlag(experimentFlagName); - return str.empty() ? defaultValue : doParse<T>(str.c_str()).value_or(defaultValue); +FlagManager& FlagManager::getMutableInstance() { + std::call_once(mOnce, [&] { + LOG_ALWAYS_FATAL_IF(mInstance, "Instance already created"); + mInstance = std::make_unique<FlagManager>(ConstructorTag{}); + }); + + return *mInstance; } -int64_t FlagManager::demo_flag() const { - std::optional<int64_t> sysPropVal = std::nullopt; - return getValue("DemoFeature__demo_flag", sysPropVal, kDemoFlag); +void FlagManager::markBootCompleted() { + mBootCompleted = true; } -bool FlagManager::use_adpf_cpu_hint() const { - std::optional<bool> sysPropVal = - doParse<bool>(base::GetProperty("debug.sf.enable_adpf_cpu_hint", "").c_str()); - return getValue("AdpfFeature__adpf_cpu_hint", sysPropVal, false); +void FlagManager::setUnitTestMode() { + mUnitTestMode = true; + + // Also set boot completed as we don't really care about it in unit testing + mBootCompleted = true; +} + +void FlagManager::dump(std::string& result) const { +#define DUMP_FLAG(name) dumpFlag(result, #name, std::bind(&FlagManager::name, this)) + + base::StringAppendF(&result, "FlagManager values: \n"); + DUMP_FLAG(use_adpf_cpu_hint); + DUMP_FLAG(use_skia_tracing); + DUMP_FLAG(connected_display); + DUMP_FLAG(dont_skip_on_early); + DUMP_FLAG(enable_small_area_detection); + DUMP_FLAG(misc1); + DUMP_FLAG(late_boot_misc2); + DUMP_FLAG(vrr_config); + DUMP_FLAG(hotplug2); + DUMP_FLAG(hdcp_level_hal); + +#undef DUMP_FLAG +} + +std::optional<bool> FlagManager::getBoolProperty(const char* property) const { + return parseBool(base::GetProperty(property, "").c_str()); +} + +bool FlagManager::getServerConfigurableFlag(const char* experimentFlagName) const { + const auto value = server_configurable_flags::GetServerConfigurableFlag(kExperimentNamespace, + experimentFlagName, ""); + const auto res = parseBool(value.c_str()); + return res.has_value() && res.value(); } -bool FlagManager::use_skia_tracing() const { - std::optional<bool> sysPropVal = - doParse<bool>(base::GetProperty(PROPERTY_SKIA_ATRACE_ENABLED, "").c_str()); - return getValue("SkiaTracingFeature__use_skia_tracing", sysPropVal, false); +#define FLAG_MANAGER_LEGACY_SERVER_FLAG(name, syspropOverride, serverFlagName) \ + bool FlagManager::name() const { \ + LOG_ALWAYS_FATAL_IF(!mBootCompleted, \ + "Can't read %s before boot completed as it is server writable", \ + __func__); \ + const auto debugOverride = getBoolProperty(syspropOverride); \ + if (debugOverride.has_value()) return debugOverride.value(); \ + return getServerConfigurableFlag(serverFlagName); \ + } + +#define FLAG_MANAGER_FLAG_INTERNAL(name, syspropOverride, checkForBootCompleted) \ + bool FlagManager::name() const { \ + if (checkForBootCompleted) { \ + LOG_ALWAYS_FATAL_IF(!mBootCompleted, \ + "Can't read %s before boot completed as it is server writable", \ + __func__); \ + } \ + static std::optional<bool> debugOverride = getBoolProperty(syspropOverride); \ + static bool value = getFlagValue([] { return flags::name(); }, debugOverride); \ + if (mUnitTestMode) { \ + /* \ + * When testing, we don't want to rely on the cached values stored in the static \ + * variables. \ + */ \ + debugOverride = getBoolProperty(syspropOverride); \ + value = getFlagValue([] { return flags::name(); }, debugOverride); \ + } \ + return value; \ + } + +#define FLAG_MANAGER_SERVER_FLAG(name, syspropOverride) \ + FLAG_MANAGER_FLAG_INTERNAL(name, syspropOverride, true) + +#define FLAG_MANAGER_READ_ONLY_FLAG(name, syspropOverride) \ + FLAG_MANAGER_FLAG_INTERNAL(name, syspropOverride, false) + +/// Legacy server flags /// +FLAG_MANAGER_LEGACY_SERVER_FLAG(test_flag, "", "") +FLAG_MANAGER_LEGACY_SERVER_FLAG(use_adpf_cpu_hint, "debug.sf.enable_adpf_cpu_hint", + "AdpfFeature__adpf_cpu_hint") +FLAG_MANAGER_LEGACY_SERVER_FLAG(use_skia_tracing, PROPERTY_SKIA_ATRACE_ENABLED, + "SkiaTracingFeature__use_skia_tracing") + +/// Trunk stable readonly flags /// +FLAG_MANAGER_READ_ONLY_FLAG(connected_display, "") +FLAG_MANAGER_READ_ONLY_FLAG(enable_small_area_detection, "") +FLAG_MANAGER_READ_ONLY_FLAG(misc1, "") +FLAG_MANAGER_READ_ONLY_FLAG(vrr_config, "debug.sf.enable_vrr_config") +FLAG_MANAGER_READ_ONLY_FLAG(hotplug2, "") +FLAG_MANAGER_READ_ONLY_FLAG(hdcp_level_hal, "") + +/// Trunk stable server flags /// +FLAG_MANAGER_SERVER_FLAG(late_boot_misc2, "") + +/// Exceptions /// +bool FlagManager::dont_skip_on_early() const { + // Even though this is a server writable flag, we do call it before boot completed, but that's + // fine since the decision is done per frame. We can't do caching though. + return flags::dont_skip_on_early(); } } // namespace android diff --git a/services/surfaceflinger/FlagManager.h b/services/surfaceflinger/FlagManager.h index e8341424e7..1a689937be 100644 --- a/services/surfaceflinger/FlagManager.h +++ b/services/surfaceflinger/FlagManager.h @@ -17,32 +17,61 @@ #pragma once #include <cstdint> +#include <mutex> #include <optional> #include <string> namespace android { // Manages flags for SurfaceFlinger, including default values, system properties, and Mendel -// experiment configuration values. +// experiment configuration values. Can be called from any thread. class FlagManager { +private: + // Effectively making the constructor private, while allowing std::make_unique to work + struct ConstructorTag {}; + public: - FlagManager() = default; + static const FlagManager& getInstance(); + static FlagManager& getMutableInstance(); + + FlagManager(ConstructorTag); virtual ~FlagManager(); + + void markBootCompleted(); void dump(std::string& result) const; - int64_t demo_flag() const; + void setUnitTestMode(); + /// Legacy server flags /// + bool test_flag() const; bool use_adpf_cpu_hint() const; - bool use_skia_tracing() const; + /// Trunk stable readonly flags /// + bool connected_display() const; + bool enable_small_area_detection() const; + bool misc1() const; + bool vrr_config() const; + bool hotplug2() const; + bool hdcp_level_hal() const; + + /// Trunk stable server flags /// + bool late_boot_misc2() const; + bool dont_skip_on_early() const; + +protected: + // overridden for unit tests + virtual std::optional<bool> getBoolProperty(const char*) const; + virtual bool getServerConfigurableFlag(const char*) const; + private: - friend class FlagManagerTest; + friend class TestableFlagManager; + + FlagManager(const FlagManager&) = delete; - // Wrapper for mocking in test. - virtual std::string getServerConfigurableFlag(const std::string& experimentFlagName) const; + std::atomic_bool mBootCompleted = false; + std::atomic_bool mUnitTestMode = false; - template <typename T> - T getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt, - T defaultValue) const; + static std::unique_ptr<FlagManager> mInstance; + static std::once_flag mOnce; }; } // namespace android diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 42676c6936..2ac7319709 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -17,9 +17,9 @@ #include <algorithm> #include "Client.h" +#include "FlagManager.h" #include "Layer.h" #include "RefreshRateOverlay.h" -#include "Utils/FlagUtils.h" #include <SkSurface.h> @@ -268,7 +268,8 @@ void RefreshRateOverlay::changeRefreshRate(Fps vsyncRate, Fps renderFps) { } void RefreshRateOverlay::changeRenderRate(Fps renderFps) { - if (mFeatures.test(Features::RenderRate) && mVsyncRate && flagutils::vrrConfigEnabled()) { + if (mFeatures.test(Features::RenderRate) && mVsyncRate && + FlagManager::getInstance().vrr_config()) { mRenderFps = renderFps; const auto buffer = getOrCreateBuffers(*mVsyncRate, renderFps)[mFrame]; createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply(); diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 9a55c94424..7f627f829d 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -45,6 +45,7 @@ #include <scheduler/VsyncConfig.h> #include "DisplayHardware/DisplayMode.h" +#include "FlagManager.h" #include "FrameTimeline.h" #include "VSyncDispatch.h" #include "VSyncTracker.h" @@ -308,7 +309,7 @@ sp<EventThreadConnection> EventThread::createEventConnection( auto connection = sp<EventThreadConnection>::make(const_cast<EventThread*>(this), IPCThreadState::self()->getCallingUid(), eventRegistration); - if (flags::misc1()) { + if (FlagManager::getInstance().misc1()) { const int policy = SCHED_FIFO; connection->setMinSchedulerPolicy(policy, sched_get_priority_min(policy)); } diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index ff829143d3..21bbb08c1c 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -21,7 +21,6 @@ #include "LayerHistory.h" #include <android-base/stringprintf.h> -#include <com_android_graphics_surfaceflinger_flags.h> #include <cutils/properties.h> #include <gui/TraceUtils.h> #include <utils/Log.h> @@ -34,16 +33,15 @@ #include "../Layer.h" #include "EventThread.h" +#include "FlagManager.h" #include "LayerInfo.h" namespace android::scheduler { namespace { -using namespace com::android::graphics::surfaceflinger; - bool isLayerActive(const LayerInfo& info, nsecs_t threshold) { - if (flags::misc1() && !info.isVisible()) { + if (FlagManager::getInstance().misc1() && !info.isVisible()) { return false; } diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index eb69d0bf22..5892b2b44c 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -38,7 +38,6 @@ #include "../SurfaceFlingerProperties.h" #include "RefreshRateSelector.h" -#include "Utils/FlagUtils.h" #include <com_android_graphics_surfaceflinger_flags.h> @@ -115,7 +114,7 @@ std::pair<unsigned, unsigned> divisorRange(Fps vsyncRate, Fps peakFps, FpsRange using fps_approx_ops::operator/; // use signed type as `fps / range.max` might be 0 auto start = std::max(1, static_cast<int>(peakFps / range.max) - 1); - if (flagutils::vrrConfigEnabled()) { + if (FlagManager::getInstance().vrr_config()) { start = std::max(1, static_cast<int>(vsyncRate / std::min(range.max, peakFps, fps_approx_ops::operator<)) - diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 5b36a5efa6..1a8713d4a9 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -47,6 +47,7 @@ #include "../Layer.h" #include "EventThread.h" +#include "FlagManager.h" #include "FrameRateOverrideMappings.h" #include "FrontEnd/LayerHandle.h" #include "OneShotTimer.h" @@ -210,7 +211,7 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, targeters.try_emplace(id, &targeter); } - if (flagutils::vrrConfigEnabled() && + if (FlagManager::getInstance().vrr_config() && CC_UNLIKELY(mPacesetterFrameDurationFractionToSkip > 0.f)) { const auto period = pacesetterTargeter.target().expectedFrameDuration(); const auto skipDuration = Duration::fromNs( diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp index f4676706fd..186a6bc9d6 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -25,16 +25,14 @@ #include <scheduler/TimeKeeper.h> +#include "FlagManager.h" #include "VSyncDispatchTimerQueue.h" #include "VSyncTracker.h" -#include <com_android_graphics_surfaceflinger_flags.h> - #undef LOG_TAG #define LOG_TAG "VSyncDispatch" namespace android::scheduler { -using namespace com::android::graphics::surfaceflinger; using base::StringAppendF; @@ -43,7 +41,8 @@ namespace { nsecs_t getExpectedCallbackTime(nsecs_t now, nsecs_t nextVsyncTime, const VSyncDispatch::ScheduleTiming& timing) { const auto expectedCallbackTime = nextVsyncTime - timing.readyDuration - timing.workDuration; - const auto baseTime = flags::dont_skip_on_early() ? now : expectedCallbackTime; + const auto baseTime = + FlagManager::getInstance().dont_skip_on_early() ? now : expectedCallbackTime; return std::max(baseTime, expectedCallbackTime); } @@ -105,7 +104,7 @@ ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTim mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance)); bool const wouldSkipAWakeup = mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance))); - if (flags::dont_skip_on_early()) { + if (FlagManager::getInstance().dont_skip_on_early()) { if (wouldSkipAVsyncTarget || wouldSkipAWakeup) { return getExpectedCallbackTime(now, mArmedInfo->mActualVsyncTime, timing); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 48be33c7ec..62eb17d2e7 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -157,15 +157,12 @@ #include "TimeStats/TimeStats.h" #include "TunnelModeEnabledReporter.h" #include "Utils/Dumper.h" -#include "Utils/FlagUtils.h" #include "WindowInfosListenerInvoker.h" #include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h> #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> #include <aidl/android/hardware/graphics/composer3/RenderIntent.h> -#include <com_android_graphics_surfaceflinger_flags.h> - #undef NO_THREAD_SAFETY_ANALYSIS #define NO_THREAD_SAFETY_ANALYSIS \ _Pragma("GCC error \"Prefer <ftl/fake_guard.h> or MutexUtils.h helpers.\"") @@ -175,8 +172,6 @@ #define DOES_CONTAIN_BORDER false namespace android { -using namespace com::android::graphics::surfaceflinger; - using namespace std::chrono_literals; using namespace std::string_literals; using namespace std::string_view_literals; @@ -509,11 +504,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true); mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); - - // Trunk-Stable flags - mMiscFlagValue = flags::misc1(); - mConnectedDisplayFlagValue = flags::connected_display(); - mMisc2FlagEarlyBootValue = flags::late_boot_misc2(); } LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { @@ -689,6 +679,7 @@ void SurfaceFlinger::bootFinished() { return; } mBootFinished = true; + FlagManager::getMutableInstance().markBootCompleted(); if (mStartPropertySetThread->join() != NO_ERROR) { ALOGE("Join StartPropertySetThread failed!"); } @@ -702,7 +693,7 @@ void SurfaceFlinger::bootFinished() { mFrameTracer->initialize(); mFrameTimeline->onBootFinished(); - getRenderEngine().setEnableTracing(mFlagManager.use_skia_tracing()); + getRenderEngine().setEnableTracing(FlagManager::getInstance().use_skia_tracing()); // wait patiently for the window manager death const String16 name("window"); @@ -731,7 +722,7 @@ void SurfaceFlinger::bootFinished() { readPersistentProperties(); mPowerAdvisor->onBootFinished(); - const bool hintSessionEnabled = mFlagManager.use_adpf_cpu_hint(); + const bool hintSessionEnabled = FlagManager::getInstance().use_adpf_cpu_hint(); mPowerAdvisor->enablePowerHintSession(hintSessionEnabled); const bool hintSessionUsed = mPowerAdvisor->usePowerHintSession(); ALOGD("Power hint is %s", @@ -755,10 +746,6 @@ void SurfaceFlinger::bootFinished() { enableRefreshRateOverlay(true); } })); - - LOG_ALWAYS_FATAL_IF(flags::misc1() != mMiscFlagValue, "misc1 flag is not boot stable!"); - - mMisc2FlagLateBootValue = flags::late_boot_misc2(); } static std::optional<renderengine::RenderEngine::RenderEngineType> @@ -2101,7 +2088,7 @@ nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const { void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp, std::optional<hal::VsyncPeriodNanos> vsyncPeriod) { - if (mConnectedDisplayFlagValue) { + if (FlagManager::getInstance().connected_display()) { // use ~0 instead of -1 as AidlComposerHal.cpp passes the param as unsigned int32 if (mIsHotplugErrViaNegVsync && timestamp < 0 && vsyncPeriod.has_value() && vsyncPeriod.value() == ~0) { @@ -4065,7 +4052,7 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) { if (sysprop::use_content_detection_for_refresh_rate(false)) { features |= Feature::kContentDetection; - if (flags::enable_small_area_detection()) { + if (FlagManager::getInstance().enable_small_area_detection()) { features |= Feature::kSmallDirtyContentDetection; } } @@ -6475,17 +6462,6 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp result.append("SurfaceFlinger global state:\n"); colorizer.reset(result); - StringAppendF(&result, "MiscFlagValue: %s\n", mMiscFlagValue ? "true" : "false"); - StringAppendF(&result, "ConnectedDisplayFlagValue: %s\n", - mConnectedDisplayFlagValue ? "true" : "false"); - StringAppendF(&result, "Misc2FlagValue: %s (%s after boot)\n", - mMisc2FlagLateBootValue ? "true" : "false", - mMisc2FlagEarlyBootValue == mMisc2FlagLateBootValue ? "stable" : "modified"); - StringAppendF(&result, "VrrConfigFlagValue: %s\n", - flagutils::vrrConfigEnabled() ? "true" : "false"); - StringAppendF(&result, "DontSkipOnEarlyFlagValue: %s\n", - flags::dont_skip_on_early() ? "true" : "false"); - getRenderEngine().dump(result); result.append("ClientCache state:\n"); @@ -6562,7 +6538,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp /* * Dump flag/property manager state */ - mFlagManager.dump(result); + FlagManager::getInstance().dump(result); result.append(mTimeStats->miniDump()); result.append("\n"); @@ -7227,7 +7203,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r // Second argument is a delay in ms for triggering the jank. This is useful for working // with tools that steal the adb connection. This argument is optional. case 1045: { - if (flagutils::vrrConfigEnabled()) { + if (FlagManager::getInstance().vrr_config()) { float jankAmount = data.readFloat(); int32_t jankDelayMs = 0; if (data.readInt32(&jankDelayMs) != NO_ERROR) { @@ -9078,7 +9054,7 @@ binder::Status SurfaceComposerAIDL::createConnection(sp<gui::ISurfaceComposerCli const sp<Client> client = sp<Client>::make(mFlinger); if (client->initCheck() == NO_ERROR) { *outClient = client; - if (flags::misc1()) { + if (FlagManager::getInstance().misc1()) { const int policy = SCHED_FIFO; client->setMinSchedulerPolicy(policy, sched_get_priority_min(policy)); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 96b67b8176..520bd221b3 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1421,8 +1421,6 @@ private: const sp<WindowInfosListenerInvoker> mWindowInfosListenerInvoker; - FlagManager mFlagManager; - // returns the framerate of the layer with the given sequence ID float getLayerFramerate(nsecs_t now, int32_t id) const { return mScheduler->getLayerFramerate(now, id); @@ -1459,12 +1457,6 @@ private: void sfdo_setDebugFlash(int delay); void sfdo_scheduleComposite(); void sfdo_scheduleCommit(); - - // Trunk-Stable flags - bool mMiscFlagValue; - bool mConnectedDisplayFlagValue; - bool mMisc2FlagEarlyBootValue; - bool mMisc2FlagLateBootValue; }; class SurfaceComposerAIDL : public gui::BnSurfaceComposer { diff --git a/services/surfaceflinger/Tracing/LayerDataSource.cpp b/services/surfaceflinger/Tracing/LayerDataSource.cpp index 25e768e0ca..ed1e2ec89c 100644 --- a/services/surfaceflinger/Tracing/LayerDataSource.cpp +++ b/services/surfaceflinger/Tracing/LayerDataSource.cpp @@ -51,8 +51,9 @@ void LayerDataSource::OnSetup(const LayerDataSource::SetupArgs& args) { if (config.has_mode() && config.mode() != LayerTracing::Mode::MODE_UNSPECIFIED) { mMode = static_cast<LayerTracing::Mode>(config.mode()); } else { - mMode = LayerTracing::Mode::MODE_GENERATED; - ALOGD("Received config with unspecified 'mode'. Using 'GENERATED' as default"); + mMode = LayerTracing::Mode::MODE_GENERATED_BUGREPORT_ONLY; + ALOGD("Received config with unspecified 'mode'." + " Using 'MODE_GENERATED_BUGREPORT_ONLY' as default"); } mFlags = 0; @@ -68,10 +69,16 @@ void LayerDataSource::OnStart(const LayerDataSource::StartArgs&) { } } -void LayerDataSource::OnFlush(const LayerDataSource::FlushArgs&) { - ALOGD("Received OnFlush event (mode = 0x%02x, flags = 0x%02x)", mMode, mFlags); +void LayerDataSource::OnFlush(const LayerDataSource::FlushArgs& args) { + ALOGD("Received OnFlush event" + " (mode = 0x%02x, flags = 0x%02x, reason = 0x%" PRIx64 ", clone_target = 0x%0" PRIx64 ")", + mMode, mFlags, args.flush_flags.reason(), args.flush_flags.clone_target()); + + bool isBugreport = args.flush_flags.reason() == perfetto::FlushFlags::Reason::kTraceClone && + args.flush_flags.clone_target() == perfetto::FlushFlags::CloneTarget::kBugreport; + if (auto* p = mLayerTracing.load()) { - p->onFlush(mMode, mFlags); + p->onFlush(mMode, mFlags, isBugreport); } } diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp index 403e1050d1..41bcdf05c3 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.cpp +++ b/services/surfaceflinger/Tracing/LayerTracing.cpp @@ -67,9 +67,27 @@ void LayerTracing::onStart(Mode mode, uint32_t flags) { break; } case Mode::MODE_GENERATED: { + // This tracing mode processes the buffer of transactions (owned by TransactionTracing), + // generates layers snapshots and writes them to perfetto. This happens every time an + // OnFlush event is received. ALOGD("Started generated tracing (waiting for OnFlush event to generated layers)"); break; } + case Mode::MODE_GENERATED_BUGREPORT_ONLY: { + // Same as MODE_GENERATED, but only when the received OnFlush event is due to a + // bugreport being taken. This mode exists because the generated layers trace is very + // large (hundreds of MB), hence we want to include it only in bugreports and not in + // field uploads. + // + // Note that perfetto communicates only whether the OnFlush event is due to a bugreport + // or not, hence we need an additional "bugreport only" tracing mode. + // If perfetto had communicated when the OnFlush is due to a field upload, then we could + // have had a single "generated" tracing mode that would have been a noop in case of + // field uploads. + ALOGD("Started 'generated bugreport only' tracing" + " (waiting for bugreport's OnFlush event to generate layers)"); + break; + } case Mode::MODE_DUMP: { auto snapshot = mTakeLayersSnapshotProto(flags); addProtoSnapshotToOstream(std::move(snapshot), Mode::MODE_DUMP); @@ -82,10 +100,18 @@ void LayerTracing::onStart(Mode mode, uint32_t flags) { } } -void LayerTracing::onFlush(Mode mode, uint32_t flags) { +void LayerTracing::onFlush(Mode mode, uint32_t flags, bool isBugreport) { // In "generated" mode process the buffer of transactions (owned by TransactionTracing), - // generate a sequence of layers snapshots and write them to perfetto. - if (mode != Mode::MODE_GENERATED) { + // generate layers snapshots and write them to perfetto. + if (mode != Mode::MODE_GENERATED && mode != Mode::MODE_GENERATED_BUGREPORT_ONLY) { + ALOGD("Skipping layers trace generation (not a 'generated' tracing session)"); + return; + } + + // In "generated bugreport only" mode skip the layers snapshot generation + // if the perfetto's OnFlush event is not due to a bugreport being taken. + if (mode == Mode::MODE_GENERATED_BUGREPORT_ONLY && !isBugreport) { + ALOGD("Skipping layers trace generation (not a bugreport OnFlush event)"); return; } @@ -147,14 +173,23 @@ void LayerTracing::writeSnapshotToStream(perfetto::protos::LayersSnapshotProto&& } void LayerTracing::writeSnapshotToPerfetto(const perfetto::protos::LayersSnapshotProto& snapshot, - Mode mode) { + Mode srcMode) { const auto snapshotBytes = snapshot.SerializeAsString(); LayerDataSource::Trace([&](LayerDataSource::TraceContext context) { - if (mode != context.GetCustomTlsState()->mMode) { + auto dstMode = context.GetCustomTlsState()->mMode; + if (srcMode == Mode::MODE_GENERATED) { + // Layers snapshots produced by LayerTraceGenerator have srcMode == MODE_GENERATED + // and should be written to tracing sessions with MODE_GENERATED + // or MODE_GENERATED_BUGREPORT_ONLY. + if (dstMode != Mode::MODE_GENERATED && dstMode != Mode::MODE_GENERATED_BUGREPORT_ONLY) { + return; + } + } else if (srcMode != dstMode) { return; } - if (!checkAndUpdateLastVsyncIdWrittenToPerfetto(mode, snapshot.vsync_id())) { + + if (!checkAndUpdateLastVsyncIdWrittenToPerfetto(srcMode, snapshot.vsync_id())) { return; } { @@ -176,7 +211,7 @@ bool LayerTracing::checkAndUpdateLastVsyncIdWrittenToPerfetto(Mode mode, std::in // In some situations (e.g. two bugreports taken shortly one after the other) the generated // sequence of layers snapshots might overlap. Here we check the snapshot's vsyncid to make // sure that in generated tracing mode a given snapshot is written only once to perfetto. - if (mode != Mode::MODE_GENERATED) { + if (mode != Mode::MODE_GENERATED && mode != Mode::MODE_GENERATED_BUGREPORT_ONLY) { return true; } diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h index fe7f06d0f6..2895ba7026 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.h +++ b/services/surfaceflinger/Tracing/LayerTracing.h @@ -55,7 +55,9 @@ class TransactionTracing; * and written to perfetto. * * - * E.g. start active mode tracing: + * E.g. start active mode tracing + * (replace mode value with MODE_DUMP, MODE_GENERATED or MODE_GENERATED_BUGREPORT_ONLY to enable + * different tracing modes): * adb shell -t perfetto \ -c - --txt \ @@ -79,7 +81,7 @@ class TransactionTracing; } } } - EOF +EOF * */ class LayerTracing { @@ -106,7 +108,7 @@ public: // Start event from perfetto data source void onStart(Mode mode, uint32_t flags); // Flush event from perfetto data source - void onFlush(Mode mode, uint32_t flags); + void onFlush(Mode mode, uint32_t flags, bool isBugreport); // Stop event from perfetto data source void onStop(Mode mode); diff --git a/services/surfaceflinger/Utils/FlagUtils.h b/services/surfaceflinger/Utils/FlagUtils.h deleted file mode 100644 index 8435f04573..0000000000 --- a/services/surfaceflinger/Utils/FlagUtils.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright 2023 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/properties.h> -#include <com_android_graphics_surfaceflinger_flags.h> -#include <string> - -namespace android::flagutils { - -using namespace std::literals::string_literals; -using namespace com::android::graphics::surfaceflinger; - -inline bool vrrConfigEnabled() { - static const bool enable_vrr_config = - base::GetBoolProperty("debug.sf.enable_vrr_config"s, false); - return flags::vrr_config() || enable_vrr_config; -} -} // namespace android::flagutils diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp index 959945230d..9889cb9c5d 100644 --- a/services/surfaceflinger/main_surfaceflinger.cpp +++ b/services/surfaceflinger/main_surfaceflinger.cpp @@ -34,6 +34,7 @@ #include <errno.h> #include <hidl/LegacySupport.h> #include <processgroup/sched_policy.h> +#include "FlagManager.h" #include "SurfaceFlinger.h" #include "SurfaceFlingerFactory.h" #include "SurfaceFlingerProperties.h" @@ -149,7 +150,7 @@ int main(int, char**) { // publish gui::ISurfaceComposer, the new AIDL interface sp<SurfaceComposerAIDL> composerAIDL = sp<SurfaceComposerAIDL>::make(flinger); - if (flags::misc1()) { + if (FlagManager::getInstance().misc1()) { composerAIDL->setMinSchedulerPolicy(SCHED_FIFO, newPriority); } sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false, diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig index 19d194f5b7..a81f9b80de 100644 --- a/services/surfaceflinger/surfaceflinger_flags.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags.aconfig @@ -52,4 +52,21 @@ flag { description: "Feature flag for SmallAreaDetection" bug: "283055450" is_fixed_read_only: true -}
\ No newline at end of file +} + +flag { + name: "hotplug2" + namespace: "core_graphics" + description: "Feature flag for using hotplug2 HAL API" + bug: "303460805" + is_fixed_read_only: true +} + +flag { + name: "hdcp_level_hal" + namespace: "core_graphics" + description: "Feature flag for adding a HAL API to commuicate hdcp levels" + bug: "285359126" + is_fixed_read_only: true +} + diff --git a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp index 0905cd14b1..aa37754300 100644 --- a/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp +++ b/services/surfaceflinger/tests/unittests/FlagManagerTest.cpp @@ -14,130 +14,153 @@ * limitations under the License. */ -#include <cstdint> #undef LOG_TAG #define LOG_TAG "FlagManagerTest" #include "FlagManager.h" +#include "FlagUtils.h" -#include <android-base/properties.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include <log/log.h> -#include <server_configurable_flags/get_flags.h> -#include <optional> + +#include <com_android_graphics_surfaceflinger_flags.h> namespace android { using testing::Return; -class MockFlagManager : public FlagManager { +class TestableFlagManager : public FlagManager { public: - MockFlagManager() = default; - ~MockFlagManager() = default; + TestableFlagManager() : FlagManager(ConstructorTag{}) { markBootCompleted(); } + ~TestableFlagManager() = default; + + MOCK_METHOD(std::optional<bool>, getBoolProperty, (const char*), (const, override)); + MOCK_METHOD(bool, getServerConfigurableFlag, (const char*), (const, override)); - MOCK_METHOD(std::string, getServerConfigurableFlag, (const std::string& experimentFlagName), - (const, override)); + void markBootIncomplete() { mBootCompleted = false; } }; class FlagManagerTest : public testing::Test { public: - FlagManagerTest(); - ~FlagManagerTest() override; - std::unique_ptr<MockFlagManager> mFlagManager; - - template <typename T> - T getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt, - T defaultValue); + FlagManagerTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + } + ~FlagManagerTest() override { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + } + + TestableFlagManager mFlagManager; }; -FlagManagerTest::FlagManagerTest() { - const ::testing::TestInfo* const test_info = - ::testing::UnitTest::GetInstance()->current_test_info(); - ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - mFlagManager = std::make_unique<MockFlagManager>(); +TEST_F(FlagManagerTest, isSingleton) { + EXPECT_EQ(&FlagManager::getInstance(), &FlagManager::getInstance()); } -FlagManagerTest::~FlagManagerTest() { - const ::testing::TestInfo* const test_info = - ::testing::UnitTest::GetInstance()->current_test_info(); - ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); +TEST_F(FlagManagerTest, legacyCreashesIfQueriedBeforeBoot) { + mFlagManager.markBootIncomplete(); + EXPECT_DEATH(FlagManager::getInstance().test_flag(), ""); } -template <typename T> -T FlagManagerTest::getValue(const std::string& experimentFlagName, - std::optional<T> systemPropertyOpt, T defaultValue) { - return mFlagManager->getValue(experimentFlagName, systemPropertyOpt, defaultValue); -} +TEST_F(FlagManagerTest, legacyReturnsOverride) { + EXPECT_CALL(mFlagManager, getBoolProperty).WillOnce(Return(true)); + EXPECT_EQ(true, mFlagManager.test_flag()); -namespace { -TEST_F(FlagManagerTest, getValue_bool_default) { - EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("")); - const bool defaultValue = false; - std::optional<bool> systemPropertyValue = std::nullopt; - const bool result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue); - ASSERT_EQ(result, defaultValue); + EXPECT_CALL(mFlagManager, getBoolProperty).WillOnce(Return(false)); + EXPECT_EQ(false, mFlagManager.test_flag()); } -TEST_F(FlagManagerTest, getValue_bool_sysprop) { - const bool defaultValue = false; - std::optional<bool> systemPropertyValue = std::make_optional(true); - const bool result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue); - ASSERT_EQ(result, true); -} +TEST_F(FlagManagerTest, legacyReturnsValue) { + EXPECT_CALL(mFlagManager, getBoolProperty).WillRepeatedly(Return(std::nullopt)); + + EXPECT_CALL(mFlagManager, getServerConfigurableFlag).WillOnce(Return(true)); + EXPECT_EQ(true, mFlagManager.test_flag()); -TEST_F(FlagManagerTest, getValue_bool_experiment) { - EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("1")); - const bool defaultValue = false; - std::optional<bool> systemPropertyValue = std::nullopt; - const bool result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue); - ASSERT_EQ(result, true); + EXPECT_CALL(mFlagManager, getServerConfigurableFlag).WillOnce(Return(false)); + EXPECT_EQ(false, mFlagManager.test_flag()); } -TEST_F(FlagManagerTest, getValue_int32_default) { - EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("")); - int32_t defaultValue = 30; - std::optional<int32_t> systemPropertyValue = std::nullopt; - int32_t result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue); - ASSERT_EQ(result, defaultValue); +TEST_F(FlagManagerTest, creashesIfQueriedBeforeBoot) { + mFlagManager.markBootIncomplete(); + EXPECT_DEATH(FlagManager::getInstance().late_boot_misc2(), ""); } -TEST_F(FlagManagerTest, getValue_int32_sysprop) { - int32_t defaultValue = 30; - std::optional<int32_t> systemPropertyValue = std::make_optional(10); - int32_t result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue); - ASSERT_EQ(result, 10); +TEST_F(FlagManagerTest, returnsOverride) { + mFlagManager.setUnitTestMode(); + + // Twice, since the first call is to initialize the static variable + EXPECT_CALL(mFlagManager, getBoolProperty) + .Times((2)) + .WillOnce(Return(true)) + .WillOnce(Return(true)); + EXPECT_EQ(true, mFlagManager.late_boot_misc2()); + + EXPECT_CALL(mFlagManager, getBoolProperty).WillOnce(Return(false)); + EXPECT_EQ(false, mFlagManager.late_boot_misc2()); } -TEST_F(FlagManagerTest, getValue_int32_experiment) { - EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("50")); - std::int32_t defaultValue = 30; - std::optional<std::int32_t> systemPropertyValue = std::nullopt; - std::int32_t result = FlagManagerTest::getValue("test_flag", systemPropertyValue, defaultValue); - ASSERT_EQ(result, 50); +TEST_F(FlagManagerTest, returnsValue) { + mFlagManager.setUnitTestMode(); + + EXPECT_CALL(mFlagManager, getBoolProperty).WillRepeatedly(Return(std::nullopt)); + + { + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::late_boot_misc2, true); + EXPECT_EQ(true, mFlagManager.late_boot_misc2()); + } + + { + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::late_boot_misc2, false); + EXPECT_EQ(false, mFlagManager.late_boot_misc2()); + } } -TEST_F(FlagManagerTest, getValue_int64_default) { - EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("")); - int64_t defaultValue = 30; - std::optional<int64_t> systemPropertyValue = std::nullopt; - int64_t result = getValue("flag_name", systemPropertyValue, defaultValue); - ASSERT_EQ(result, defaultValue); +TEST_F(FlagManagerTest, readonlyReturnsOverride) { + mFlagManager.setUnitTestMode(); + + // Twice, since the first call is to initialize the static variable + EXPECT_CALL(mFlagManager, getBoolProperty) + .Times(2) + .WillOnce(Return(true)) + .WillOnce(Return(true)); + EXPECT_EQ(true, mFlagManager.misc1()); + + EXPECT_CALL(mFlagManager, getBoolProperty).WillOnce(Return(false)); + EXPECT_EQ(false, mFlagManager.misc1()); } -TEST_F(FlagManagerTest, getValue_int64_sysprop) { - int64_t defaultValue = 30; - std::optional<int64_t> systemPropertyValue = std::make_optional(10); - int64_t result = getValue("flag_name", systemPropertyValue, defaultValue); - ASSERT_EQ(result, 10); +TEST_F(FlagManagerTest, readonlyReturnsValue) { + mFlagManager.setUnitTestMode(); + + EXPECT_CALL(mFlagManager, getBoolProperty).WillRepeatedly(Return(std::nullopt)); + + { + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::misc1, true); + EXPECT_EQ(true, mFlagManager.misc1()); + } + + { + SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::misc1, false); + EXPECT_EQ(false, mFlagManager.misc1()); + } } -TEST_F(FlagManagerTest, getValue_int64_experiment) { - EXPECT_CALL(*mFlagManager, getServerConfigurableFlag).Times(1).WillOnce(Return("50")); - int64_t defaultValue = 30; - std::optional<int64_t> systemPropertyValue = std::nullopt; - int64_t result = getValue("flag_name", systemPropertyValue, defaultValue); - ASSERT_EQ(result, 50); +TEST_F(FlagManagerTest, dontSkipOnEarlyIsNotCached) { + EXPECT_CALL(mFlagManager, getBoolProperty).WillRepeatedly(Return(std::nullopt)); + + const auto initialValue = com::android::graphics::surfaceflinger::flags::dont_skip_on_early(); + + com::android::graphics::surfaceflinger::flags::dont_skip_on_early(true); + EXPECT_EQ(true, mFlagManager.dont_skip_on_early()); + + com::android::graphics::surfaceflinger::flags::dont_skip_on_early(false); + EXPECT_EQ(false, mFlagManager.dont_skip_on_early()); + + com::android::graphics::surfaceflinger::flags::dont_skip_on_early(initialValue); } -} // namespace + } // namespace android diff --git a/services/surfaceflinger/tests/unittests/FlagUtils.h b/services/surfaceflinger/tests/unittests/FlagUtils.h index 7103684577..333e4e7e05 100644 --- a/services/surfaceflinger/tests/unittests/FlagUtils.h +++ b/services/surfaceflinger/tests/unittests/FlagUtils.h @@ -16,12 +16,16 @@ #pragma once +#include "FlagManager.h" + #define SET_FLAG_FOR_TEST(name, value) TestFlagSetter _testflag_((name), (name), (value)) namespace android { class TestFlagSetter { public: TestFlagSetter(bool (*getter)(), void((*setter)(bool)), bool flagValue) { + FlagManager::getMutableInstance().setUnitTestMode(); + const bool initialValue = getter(); setter(flagValue); mResetFlagValue = [=] { setter(initialValue); }; |