Merge changes I53f65dae,I4bbfe4c5 into main
* changes:
Count active touches in MultiTouchMotionAccumulator
Record last keypress timestamp on physical keyboard while typing
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 4f80190..17e5cc1 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1089,8 +1089,14 @@
// 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 @@
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 @@
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::PreDumpUiData() {
+ MaybeSnapshotSystemTrace();
MaybeSnapshotUiTraces();
}
@@ -3264,25 +3263,23 @@
// 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::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 @@
// 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 @@
"", 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 d01cfce..c66fd1c 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -476,11 +476,6 @@
// 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 @@
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 a417837..fc82886 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -1000,7 +1000,6 @@
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 822ab7f..8eb7458 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -514,6 +514,8 @@
// 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 c40caf5..c86adef 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -353,7 +353,7 @@
// 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 2e99495..ee74455 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -98,7 +98,7 @@
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 f22e90a..8243238 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 @@
bool mInheritRt = false;
// for below objects
- Mutex mLock;
+ RpcMutex mLock;
std::set<sp<RpcServerLink>> mRpcServerLinks;
BpBinder::ObjectManager mObjects;
@@ -307,7 +306,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
Extras* e = getOrCreateExtras();
LOG_ALWAYS_FATAL_IF(!e, "no memory");
- AutoMutex _l(e->mLock);
+ RpcMutexUniqueLock _l(e->mLock);
doWithLock();
}
@@ -485,7 +484,7 @@
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 @@
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 @@
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 3bc4f92..49038b1 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 @@
// ---------------------------------------------------------------------------
-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 @@
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 @@
}
bool BpBinder::isDescriptorCached() const {
- Mutex::Autolock _l(mLock);
+ RpcMutexUniqueLock _l(mLock);
return mDescriptorCache.c_str() != kDescriptorUninit.c_str();
}
@@ -292,7 +291,7 @@
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 = 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 @@
"linkToDeath(): recipient must be non-NULL");
{
- AutoMutex _l(mLock);
+ RpcMutexUniqueLock _l(mLock);
if (!mObitsSent) {
if (!mObituaries) {
@@ -467,7 +466,7 @@
return INVALID_OPERATION;
}
- AutoMutex _l(mLock);
+ RpcMutexUniqueLock _l(mLock);
if (mObitsSent) {
return DEAD_OBJECT;
@@ -555,30 +554,30 @@
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 @@
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 @@
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 @@
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::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 c6e4fb3..7ae616e 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 2780bd4..dea2603 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 cd92217..60ece72 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 6034f2b..fe566fc 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -200,7 +200,7 @@
}
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 5b1cb7e..95bdbb4 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -155,7 +155,7 @@
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::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 @@
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(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 a3ff7d2..6d2e12b 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 8ec4af9..58203c1 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -189,7 +189,7 @@
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 @@
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> 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 @@
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 07ab093..1011571 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 fa8f2b5..c8aff63 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 5046253..749c2f8 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 @@
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 @@
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 @@
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 @@
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 @@
// 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 dd632c0..8942c31 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 28fb9f1..d78ea0d 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 @@
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 @@
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 98d12bb..6961abc 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 9dc370b..3672702 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 @@
// 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 5bf9680..f2693dd 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::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 @@
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 @@
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 341e9ce..659943a 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 1340ea1..bc34d4c 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 @@
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 @@
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 eceff35..c3070dd 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 @@
#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::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 cb632e9..aaca8d0 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 fcb83bd..8acaae6 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 1c13866..cbbbe74 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/binder/tests/format.h b/libs/binder/tests/format.h
new file mode 100644
index 0000000..b5440a4
--- /dev/null
+++ b/libs/binder/tests/format.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+// 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.
+
+#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 416ffad..ffeca2d 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 e494366..f3006cd 100644
--- a/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/RecordedTransactionFileFuzz.cpp
@@ -35,7 +35,7 @@
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 975f689..e46ccfb 100644
--- a/libs/binder/trusty/binderRpcTest/rules.mk
+++ b/libs/binder/trusty/binderRpcTest/rules.mk
@@ -21,6 +21,7 @@
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 5d1a51d..50ae3d2 100644
--- a/libs/binder/trusty/binderRpcTest/service/rules.mk
+++ b/libs/binder/trusty/binderRpcTest/service/rules.mk
@@ -21,6 +21,7 @@
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 d4605ea..3fe71ce 100644
--- a/libs/bufferqueueconverter/Android.bp
+++ b/libs/bufferqueueconverter/Android.bp
@@ -34,5 +34,7 @@
"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 0ecf94c..d6305f8 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 872193c..a5e2fa8 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 0000000..ff3ae5a
--- /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 0000000..a2db934
--- /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 0000000..46ce028
--- /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 0000000..5efee92
--- /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 0000000..8cba857
--- /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 67b95a5..0000000
--- 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 0000000..f3f4404
--- /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 0000000..d85ea72
--- /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 0000000..fccd93a
--- /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 0000000..06814ea
--- /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 34e0eb4..3d3fee4 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 79fb331..0000000
--- 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 e652102..75c8ab5 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 0000000..eeb308a
--- /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 9ebaf16..47607a0 100644
--- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -104,7 +104,7 @@
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 f17a654..c84ee1f 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -20,6 +20,25 @@
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 @@
"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 @@
},
}
-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 @@
"libbinder",
"libGLESv2",
],
+ export_static_lib_headers: [
+ "libguiflags",
+ ],
}
cc_library_shared {
@@ -460,6 +471,7 @@
static_libs: [
"libgtest",
"libgmock",
+ "libguiflags",
],
srcs: [
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index dd0a028..8d0331e 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 @@
}
}
-#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 ab0f6d2..b0f6e69 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 @@
}
}
-#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 67dff6d..19693e3 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 @@
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 6993bfa..11524e2 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 @@
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 d0c09e4..e81c098 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 @@
}
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 @@
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 @@
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 a87f053..07a0cfe 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 @@
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 02d7c4d..892215e 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 @@
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 2756277..0948c4d0 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 @@
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 38805d0..de47483 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 @@
// 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/Flags.h b/libs/gui/include/gui/Flags.h
deleted file mode 100644
index a2cff56..0000000
--- a/libs/gui/include/gui/Flags.h
+++ /dev/null
@@ -1,22 +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
-
-// 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
-#endif
\ No newline at end of file
diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
index e183bf2..51d3959 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 @@
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 3562906..7639e70 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 @@
// 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 38c0eed..6dcd501 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -21,7 +21,7 @@
"-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 17aa5f1..1410c7d 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -1266,9 +1266,7 @@
}
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 116b778..613a0df 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -275,10 +275,10 @@
}
}
-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 @@
// 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 @@
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 @@
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 978a80f..3672387 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -48,3 +48,17 @@
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 bbc6d98..5f05a0f 100644
--- a/libs/input/rust/input_verifier.rs
+++ b/libs/input/rust/input_verifier.rs
@@ -118,18 +118,17 @@
match action.into() {
MotionAction::Down => {
+ 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, self.touching_pointer_ids_by_device
+ ));
+ }
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) {
- return Err(format!(
- "{}: Invalid DOWN event - pointers already down for device {:?}: {:?}",
- self.name, device_id, it
- ));
- }
- it.insert(pointer_id);
+ 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 @@
}
#[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 1c8ec90..f9ca280 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -229,41 +229,23 @@
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 @@
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 @@
{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 @@
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 @@
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 @@
{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 32fb350..099f47d 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 @@
/**
* 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 c2535e0..3a09204 100644
--- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
+++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp
@@ -515,7 +515,7 @@
}
}
-#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 0eeca54..86dcaef 100644
--- a/libs/permission/Android.bp
+++ b/libs/permission/Android.bp
@@ -20,6 +20,12 @@
],
}
+filegroup {
+ name: "framework-permission-aidl-filegroup",
+ srcs: ["aidl/android/**/*.aidl"],
+ path: "aidl",
+}
+
cc_library {
name: "libpermission",
host_supported: true,
@@ -35,6 +41,7 @@
"-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 6959274..b407d02 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 @@
return gClientId;
}
+
+static std::string getString(const String16& stringToConvert) {
+ return std::string(String8(stringToConvert).c_str());
+}
+
AppOpsManager::AppOpsManager()
{
}
@@ -78,9 +86,14 @@
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& 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 @@
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& 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 7f235a4..33dd24d 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 @@
{
}
- 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 @@
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 @@
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 @@
{
//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 918fcdb..a5fdc54 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 @@
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 7b2f39c..04e2fff 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -567,7 +567,6 @@
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_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 d447d1e..f06a045 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -163,11 +163,11 @@
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 ee0ab33..d9d0450 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 @@
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 @@
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 @@
}
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 @@
result.push_back(args);
return result;
}
- if (isUpOrCancel) {
+ if (isDisengageOrCancel) {
mActiveStyli.erase(args.deviceId);
}
// Never drop stylus events
@@ -158,7 +169,7 @@
}
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 @@
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 c7d98ab..c889b9b 100644
--- a/services/inputflinger/dispatcher/DebugConfig.h
+++ b/services/inputflinger/dispatcher/DebugConfig.h
@@ -69,6 +69,16 @@
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 7dfbf94..47b9a0c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -756,10 +756,6 @@
// --- 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 @@
mMaximumObscuringOpacityForTouch(1.0f),
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mWindowTokenWithPointerCapture(nullptr),
- mStaleEventTimeout(staleEventTimeout),
mLatencyAggregator(),
mLatencyTracker(&mLatencyAggregator) {
mLooper = sp<Looper>::make(false);
@@ -956,20 +951,25 @@
// 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 @@
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 @@
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 @@
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 @@
}
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
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 @@
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::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 @@
}
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 @@
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 @@
// 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 a1127a0..e428c4e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -82,8 +82,6 @@
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 @@
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 @@
*/
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 af28e48..bf48804 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 @@
/* 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 3c87f71..2509c60 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -112,8 +112,6 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
}
/**
+ * 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 @@
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 1775a7a..f32fb3a 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 DisplayModes = ftl::SmallMap<DisplayModeId, DisplayModePtr, 3>;
using DisplayModeIterator = DisplayModes::const_iterator;
-using namespace com::android::graphics::surfaceflinger;
class DisplayMode {
public:
@@ -140,7 +139,7 @@
// 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 f8ad8f6..11a5e0d 100644
--- a/services/surfaceflinger/FlagManager.cpp
+++ b/services/surfaceflinger/FlagManager.cpp
@@ -26,37 +26,21 @@
#include <server_configurable_flags/get_flags.h>
#include <cinttypes>
-namespace android {
-static constexpr const char* kExperimentNamespace = "surface_flinger_native_boot";
-static constexpr const int64_t kDemoFlag = -1;
+#include <com_android_graphics_surfaceflinger_flags.h>
+namespace android {
+using namespace com::android::graphics::surfaceflinger;
+
+static constexpr const char* kExperimentNamespace = "surface_flinger_native_boot";
+
+std::unique_ptr<FlagManager> FlagManager::mInstance;
+std::once_flag FlagManager::mOnce;
+
+FlagManager::FlagManager(ConstructorTag) {}
FlagManager::~FlagManager() = default;
-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");
-}
-
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 @@
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;
+FlagManager& FlagManager::getMutableInstance() {
+ std::call_once(mOnce, [&] {
+ LOG_ALWAYS_FATAL_IF(mInstance, "Instance already created");
+ mInstance = std::make_unique<FlagManager>(ConstructorTag{});
+ });
+
+ return *mInstance;
+}
+
+void FlagManager::markBootCompleted() {
+ mBootCompleted = true;
+}
+
+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();
+}
+
+#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); \
}
- std::string str = getServerConfigurableFlag(experimentFlagName);
- return str.empty() ? defaultValue : doParse<T>(str.c_str()).value_or(defaultValue);
-}
-int64_t FlagManager::demo_flag() const {
- std::optional<int64_t> sysPropVal = std::nullopt;
- return getValue("DemoFeature__demo_flag", sysPropVal, kDemoFlag);
-}
+#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; \
+ }
-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);
-}
+#define FLAG_MANAGER_SERVER_FLAG(name, syspropOverride) \
+ FLAG_MANAGER_FLAG_INTERNAL(name, syspropOverride, true)
-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_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 e834142..1a68993 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;
- // Wrapper for mocking in test.
- virtual std::string getServerConfigurableFlag(const std::string& experimentFlagName) const;
+ FlagManager(const FlagManager&) = delete;
- template <typename T>
- T getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt,
- T defaultValue) const;
+ std::atomic_bool mBootCompleted = false;
+ std::atomic_bool mUnitTestMode = false;
+
+ 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 42676c6..2ac7319 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::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 9a55c94..7f627f8 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 @@
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 ff82914..21bbb08 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 eb69d0b..5892b2b 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 @@
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 5b36a5e..1a8713d 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 @@
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 f467670..186a6bc 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 @@
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 @@
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 48be33c..62eb17d 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 @@
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 @@
return;
}
mBootFinished = true;
+ FlagManager::getMutableInstance().markBootCompleted();
if (mStartPropertySetThread->join() != NO_ERROR) {
ALOGE("Join StartPropertySetThread failed!");
}
@@ -702,7 +693,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/*
* Dump flag/property manager state
*/
- mFlagManager.dump(result);
+ FlagManager::getInstance().dump(result);
result.append(mTimeStats->miniDump());
result.append("\n");
@@ -7227,7 +7203,7 @@
// 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 @@
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 96b67b8..520bd22 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1421,8 +1421,6 @@
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 @@
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 25e768e..ed1e2ec 100644
--- a/services/surfaceflinger/Tracing/LayerDataSource.cpp
+++ b/services/surfaceflinger/Tracing/LayerDataSource.cpp
@@ -51,8 +51,9 @@
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::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 403e105..41bcdf0 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -67,9 +67,27 @@
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::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::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 @@
// 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 fe7f06d..2895ba7 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.h
+++ b/services/surfaceflinger/Tracing/LayerTracing.h
@@ -55,7 +55,9 @@
* 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 @@
}
}
}
- EOF
+EOF
*
*/
class LayerTracing {
@@ -106,7 +108,7 @@
// 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 8435f04..0000000
--- 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 9599452..9889cb9 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 @@
// 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 19d194f..a81f9b8 100644
--- a/services/surfaceflinger/surfaceflinger_flags.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags.aconfig
@@ -52,4 +52,21 @@
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 0905cd1..aa37754 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::string, getServerConfigurableFlag, (const std::string& experimentFlagName),
- (const, override));
+ MOCK_METHOD(std::optional<bool>, getBoolProperty, (const char*), (const, override));
+ MOCK_METHOD(bool, getServerConfigurableFlag, (const char*), (const, override));
+
+ void markBootIncomplete() { mBootCompleted = false; }
};
class FlagManagerTest : public testing::Test {
public:
- FlagManagerTest();
- ~FlagManagerTest() override;
- std::unique_ptr<MockFlagManager> mFlagManager;
+ 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());
+ }
- template <typename T>
- T getValue(const std::string& experimentFlagName, std::optional<T> systemPropertyOpt,
- T defaultValue);
+ 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());
+
+ EXPECT_CALL(mFlagManager, getBoolProperty).WillOnce(Return(false));
+ EXPECT_EQ(false, 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);
+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());
+
+ EXPECT_CALL(mFlagManager, getServerConfigurableFlag).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, creashesIfQueriedBeforeBoot) {
+ mFlagManager.markBootIncomplete();
+ EXPECT_DEATH(FlagManager::getInstance().late_boot_misc2(), "");
}
-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);
+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_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, 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_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, 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_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, 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_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, 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);
}
-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, 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);
-}
-} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/FlagUtils.h b/services/surfaceflinger/tests/unittests/FlagUtils.h
index 7103684..333e4e7 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); };