Merge "Make dumpstate logs less verbose"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 8371e3c..9d6a7ff 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1545,11 +1545,7 @@
* Returns RunStatus::USER_DENIED_CONSENT if user explicitly denied consent to sharing the bugreport
* with the caller.
*/
-static Dumpstate::RunStatus DumpstateDefault() {
- // Invoking the following dumpsys calls before DumpTraces() to try and
- // keep the system stats as close to its initial state as possible.
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);
-
+Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() {
// Capture first logcat early on; useful to take a snapshot before dumpstate logs take over the
// buffer.
DoLogcat();
@@ -1634,6 +1630,7 @@
// This method collects dumpsys for telephony debugging only
static void DumpstateTelephonyOnly() {
DurationReporter duration_reporter("DUMPSTATE");
+
const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
DumpstateRadioCommon();
@@ -2346,11 +2343,6 @@
MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n",
calling_uid, calling_package.c_str());
- if (CalledByApi()) {
- // If the output needs to be copied over to the caller's fd, get user consent.
- android::String16 package(calling_package.c_str());
- CheckUserConsent(calling_uid, package);
- }
// Redirect output if needed
bool is_redirecting = options_->OutputToFile();
@@ -2489,13 +2481,23 @@
PrintHeader();
if (options_->telephony_only) {
+ MaybeCheckUserConsent(calling_uid, calling_package);
DumpstateTelephonyOnly();
DumpstateBoard();
} else if (options_->wifi_only) {
+ MaybeCheckUserConsent(calling_uid, calling_package);
DumpstateWifiOnly();
} else {
+ // Invoking the critical dumpsys calls before DumpTraces() to try and
+ // keep the system stats as close to its initial state as possible.
+ RunDumpsysCritical();
+
+ // Run consent check only after critical dumpsys has finished -- so the consent
+ // isn't going to pollute the system state / logs.
+ MaybeCheckUserConsent(calling_uid, calling_package);
+
// Dump state for the default case. This also drops root.
- RunStatus s = DumpstateDefault();
+ RunStatus s = DumpstateDefaultAfterCritical();
if (s != RunStatus::OK) {
if (s == RunStatus::USER_CONSENT_DENIED) {
HandleUserConsentDenied();
@@ -2580,17 +2582,20 @@
: RunStatus::OK;
}
-void Dumpstate::CheckUserConsent(int32_t calling_uid, const android::String16& calling_package) {
- if (calling_uid == AID_SHELL) {
+void Dumpstate::MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package) {
+ if (calling_uid == AID_SHELL || !CalledByApi()) {
+ // No need to get consent for shell triggered dumpstates, or not through
+ // bugreporting API (i.e. no fd to copy back).
return;
}
consent_callback_ = new ConsentCallback();
const String16 incidentcompanion("incidentcompanion");
sp<android::IBinder> ics(defaultServiceManager()->getService(incidentcompanion));
+ android::String16 package(calling_package.c_str());
if (ics != nullptr) {
MYLOGD("Checking user consent via incidentcompanion service\n");
android::interface_cast<android::os::IIncidentCompanion>(ics)->authorizeReport(
- calling_uid, calling_package, String16(), String16(),
+ calling_uid, package, String16(), String16(),
0x1 /* FLAG_CONFIRMATION_DIALOG */, consent_callback_.get());
} else {
MYLOGD("Unable to check user consent; incidentcompanion service unavailable\n");
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 831574d..7d9b113 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -486,7 +486,9 @@
private:
RunStatus RunInternal(int32_t calling_uid, const std::string& calling_package);
- void CheckUserConsent(int32_t calling_uid, const android::String16& calling_package);
+ RunStatus DumpstateDefaultAfterCritical();
+
+ void MaybeCheckUserConsent(int32_t calling_uid, const std::string& calling_package);
// Removes the in progress files output files (tmp file, zip/txt file, screenshot),
// but leaves the log file alone.
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index bb92fd3..5476319 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -36,7 +36,10 @@
defaults: ["idlcli-defaults"],
srcs: [
"CommandVibrator.cpp",
+ "vibrator/CommandCompose.cpp",
"vibrator/CommandGetCapabilities.cpp",
+ "vibrator/CommandGetCompositionDelayMax.cpp",
+ "vibrator/CommandGetCompositionSizeMax.cpp",
"vibrator/CommandOff.cpp",
"vibrator/CommandOn.cpp",
"vibrator/CommandPerform.cpp",
diff --git a/cmds/idlcli/vibrator/CommandCompose.cpp b/cmds/idlcli/vibrator/CommandCompose.cpp
new file mode 100644
index 0000000..705e40b
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandCompose.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+using aidl::CompositeEffect;
+
+class CommandCompose : public Command {
+ std::string getDescription() const override { return "Compose vibration."; }
+
+ std::string getUsageSummary() const override { return "<delay> <primitive> <scale> ..."; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{
+ {"<delay>", {"In milliseconds"}},
+ {"<primitive>", {"Primitive ID."}},
+ {"<scale>", {"0.0 (exclusive) - 1.0 (inclusive)."}},
+ {"...", {"May repeat multiple times."}},
+ };
+ return details;
+ }
+
+ Status doArgs(Args &args) override {
+ while (!args.empty()) {
+ CompositeEffect effect;
+ if (auto delay = args.pop<decltype(effect.delayMs)>()) {
+ effect.delayMs = *delay;
+ std::cout << "Delay: " << effect.delayMs << std::endl;
+ } else {
+ std::cerr << "Missing or Invalid Delay!" << std::endl;
+ return USAGE;
+ }
+ // TODO: Use range validation when supported by AIDL
+ if (auto primitive = args.pop<std::underlying_type_t<decltype(effect.primitive)>>()) {
+ effect.primitive = static_cast<decltype(effect.primitive)>(*primitive);
+ std::cout << "Primitive: " << toString(effect.primitive) << std::endl;
+ } else {
+ std::cerr << "Missing or Invalid Primitive!" << std::endl;
+ return USAGE;
+ }
+ if (auto scale = args.pop<decltype(effect.scale)>();
+ scale && *scale > 0.0 && scale <= 1.0) {
+ effect.scale = *scale;
+ std::cout << "Scale: " << effect.scale << std::endl;
+ } else {
+ std::cerr << "Missing or Invalid Scale!" << std::endl;
+ return USAGE;
+ }
+ mComposite.emplace_back(std::move(effect));
+ }
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }
+
+ Status doMain(Args && /*args*/) override {
+ std::string statusStr;
+ Status ret;
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::compose, mComposite, nullptr);
+ statusStr = status.toString8();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+
+ return ret;
+ }
+
+ std::vector<CompositeEffect> mComposite;
+};
+
+static const auto Command = CommandRegistry<CommandVibrator>::Register<CommandCompose>("compose");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp b/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp
new file mode 100644
index 0000000..b414307
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetCompositionDelayMax : public Command {
+ std::string getDescription() const override {
+ return "Retrieves vibrator composition delay max.";
+ }
+
+ std::string getUsageSummary() const override { return ""; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{};
+ return details;
+ }
+
+ Status doArgs(Args &args) override {
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }
+
+ Status doMain(Args && /*args*/) override {
+ std::string statusStr;
+ int32_t maxDelayMs;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::getCompositionDelayMax, &maxDelayMs);
+ statusStr = status.toString8();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Max Delay: " << maxDelayMs << " ms" << std::endl;
+
+ return ret;
+ }
+};
+
+static const auto Command =
+ CommandRegistry<CommandVibrator>::Register<CommandGetCompositionDelayMax>(
+ "getCompositionDelayMax");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp b/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp
new file mode 100644
index 0000000..360fc9d
--- /dev/null
+++ b/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utils.h"
+#include "vibrator.h"
+
+namespace android {
+namespace idlcli {
+
+class CommandVibrator;
+
+namespace vibrator {
+
+class CommandGetCompositionSizeMax : public Command {
+ std::string getDescription() const override {
+ return "Retrieves vibrator composition size max.";
+ }
+
+ std::string getUsageSummary() const override { return ""; }
+
+ UsageDetails getUsageDetails() const override {
+ UsageDetails details{};
+ return details;
+ }
+
+ Status doArgs(Args &args) override {
+ if (!args.empty()) {
+ std::cerr << "Unexpected Arguments!" << std::endl;
+ return USAGE;
+ }
+ return OK;
+ }
+
+ Status doMain(Args && /*args*/) override {
+ std::string statusStr;
+ int32_t maxSize;
+ Status ret;
+
+ if (auto hal = getHal<aidl::IVibrator>()) {
+ auto status = hal->call(&aidl::IVibrator::getCompositionSizeMax, &maxSize);
+ statusStr = status.toString8();
+ ret = status.isOk() ? OK : ERROR;
+ } else {
+ return UNAVAILABLE;
+ }
+
+ std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Max Size: " << maxSize << std::endl;
+
+ return ret;
+ }
+};
+
+static const auto Command =
+ CommandRegistry<CommandVibrator>::Register<CommandGetCompositionSizeMax>(
+ "getCompositionSizeMax");
+
+} // namespace vibrator
+} // namespace idlcli
+} // namespace android
diff --git a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
index 6e2261f..33d7eed 100644
--- a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
+++ b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
@@ -54,7 +54,8 @@
Status ret;
if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::setAmplitude, mAmplitude);
+ auto status = hal->call(&aidl::IVibrator::setAmplitude,
+ static_cast<float>(mAmplitude) / UINT8_MAX);
statusStr = status.toString8();
ret = status.isOk() ? OK : ERROR;
} else if (auto hal = getHal<V1_0::IVibrator>()) {
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 94d90ad..d39ee25 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -121,11 +121,16 @@
float yCursorPosition;
uint32_t pointerCount;
uint32_t empty3;
- // Note that PointerCoords requires 8 byte alignment.
+ /**
+ * The "pointers" field must be the last field of the struct InputMessage.
+ * When we send the struct InputMessage across the socket, we are not
+ * writing the entire "pointers" array, but only the pointerCount portion
+ * of it as an optimization. Adding a field after "pointers" would break this.
+ */
struct Pointer {
PointerProperties properties;
PointerCoords coords;
- } pointers[MAX_POINTERS];
+ } pointers[MAX_POINTERS] __attribute__((aligned(8)));
int32_t getActionId() const {
uint32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
@@ -141,7 +146,7 @@
struct Finished {
uint32_t seq;
- bool handled;
+ uint32_t handled; // actually a bool, but we must maintain 8-byte alignment
inline size_t size() const {
return sizeof(Finished);
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 3c31d74..06a5f06 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#undef LOG_TAG
+#define LOG_TAG "BLASTBufferQueue"
+
#include <gui/BLASTBufferQueue.h>
#include <gui/BufferItemConsumer.h>
@@ -24,8 +27,14 @@
namespace android {
BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height)
- : mSurfaceControl(surface), mWidth(width), mHeight(height) {
+ : mSurfaceControl(surface),
+ mPendingCallbacks(0),
+ mWidth(width),
+ mHeight(height),
+ mNextTransaction(nullptr) {
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ mConsumer->setMaxBufferCount(MAX_BUFFERS);
+ mProducer->setMaxDequeuedBufferCount(MAX_BUFFERS - 1);
mBufferItemConsumer =
new BufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
mBufferItemConsumer->setName(String8("BLAST Consumer"));
@@ -34,6 +43,8 @@
mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888);
mBufferItemConsumer->setTransformHint(mSurfaceControl->getTransformHint());
+
+ mAcquired = false;
}
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, int width, int height) {
@@ -59,20 +70,32 @@
const std::vector<SurfaceControlStats>& stats) {
std::unique_lock _lock{mMutex};
- if (stats.size() > 0 && mNextCallbackBufferItem.mGraphicBuffer != nullptr) {
+ if (stats.size() > 0 && !mShadowQueue.empty()) {
mBufferItemConsumer->releaseBuffer(mNextCallbackBufferItem,
stats[0].previousReleaseFence
? stats[0].previousReleaseFence
: Fence::NO_FENCE);
+ mAcquired = false;
mNextCallbackBufferItem = BufferItem();
mBufferItemConsumer->setTransformHint(stats[0].transformHint);
}
- mDequeueWaitCV.notify_all();
+ mPendingCallbacks--;
+ processNextBufferLocked();
+ mCallbackCV.notify_all();
decStrong((void*)transactionCallbackThunk);
}
-void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
- std::unique_lock _lock{mMutex};
+void BLASTBufferQueue::processNextBufferLocked() {
+ if (mShadowQueue.empty()) {
+ return;
+ }
+
+ if (mAcquired) {
+ return;
+ }
+
+ BufferItem item = std::move(mShadowQueue.front());
+ mShadowQueue.pop();
SurfaceComposerClient::Transaction localTransaction;
bool applyTransaction = true;
@@ -83,11 +106,11 @@
applyTransaction = false;
}
- int status = OK;
mNextCallbackBufferItem = mLastSubmittedBufferItem;
-
mLastSubmittedBufferItem = BufferItem();
- status = mBufferItemConsumer->acquireBuffer(&mLastSubmittedBufferItem, -1, false);
+
+ status_t status = mBufferItemConsumer->acquireBuffer(&mLastSubmittedBufferItem, -1, false);
+ mAcquired = true;
if (status != OK) {
ALOGE("Failed to acquire?");
}
@@ -99,7 +122,6 @@
return;
}
-
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
@@ -112,17 +134,21 @@
t->setCrop(mSurfaceControl, {0, 0, (int32_t)buffer->getWidth(), (int32_t)buffer->getHeight()});
if (applyTransaction) {
- ALOGE("Apply transaction");
t->apply();
-
- if (mNextCallbackBufferItem.mGraphicBuffer != nullptr) {
- mDequeueWaitCV.wait_for(_lock, 5000ms);
- }
}
}
+void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
+ std::lock_guard _lock{mMutex};
+
+ // add to shadow queue
+ mShadowQueue.push(item);
+ processNextBufferLocked();
+ mPendingCallbacks++;
+}
+
void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) {
- std::unique_lock _lock{mMutex};
+ std::lock_guard _lock{mMutex};
mNextTransaction = t;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 2ab4d8a..6bdbe77 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -189,48 +189,49 @@
}
void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
- std::lock_guard<std::mutex> lock(mMutex);
+ std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
- /* This listener knows all the sp<IBinder> to sp<SurfaceControl> for all its registered
- * callbackIds, except for when Transactions are merged together. This probably cannot be
- * solved before this point because the Transactions could be merged together and applied in a
- * different process.
- *
- * Fortunately, we get all the callbacks for this listener for the same frame together at the
- * same time. This means if any Transactions were merged together, we will get their callbacks
- * at the same time. We can combine all the sp<IBinder> to sp<SurfaceControl> maps for all the
- * callbackIds to generate one super map that contains all the sp<IBinder> to sp<SurfaceControl>
- * that could possibly exist for the callbacks.
- */
- std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash>
- surfaceControls;
- for (const auto& transactionStats : listenerStats.transactionStats) {
- for (auto callbackId : transactionStats.callbackIds) {
- auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
- surfaceControls.insert(callbackSurfaceControls.begin(), callbackSurfaceControls.end());
+ /* This listener knows all the sp<IBinder> to sp<SurfaceControl> for all its registered
+ * callbackIds, except for when Transactions are merged together. This probably cannot be
+ * solved before this point because the Transactions could be merged together and applied in
+ * a different process.
+ *
+ * Fortunately, we get all the callbacks for this listener for the same frame together at
+ * the same time. This means if any Transactions were merged together, we will get their
+ * callbacks at the same time. We can combine all the sp<IBinder> to sp<SurfaceControl> maps
+ * for all the callbackIds to generate one super map that contains all the sp<IBinder> to
+ * sp<SurfaceControl> that could possibly exist for the callbacks.
+ */
+ callbacksMap = mCallbacks;
+ for (const auto& transactionStats : listenerStats.transactionStats) {
+ for (auto& callbackId : transactionStats.callbackIds) {
+ mCallbacks.erase(callbackId);
+ }
}
}
-
for (const auto& transactionStats : listenerStats.transactionStats) {
for (auto callbackId : transactionStats.callbackIds) {
- auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
+ auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId];
if (!callbackFunction) {
ALOGE("cannot call null callback function, skipping");
continue;
}
std::vector<SurfaceControlStats> surfaceControlStats;
for (const auto& surfaceStats : transactionStats.surfaceStats) {
- surfaceControlStats.emplace_back(surfaceControls[surfaceStats.surfaceControl],
- surfaceStats.acquireTime,
- surfaceStats.previousReleaseFence,
- surfaceStats.transformHint);
- surfaceControls[surfaceStats.surfaceControl]->setTransformHint(
- surfaceStats.transformHint);
+ surfaceControlStats
+ .emplace_back(callbacksMap[callbackId]
+ .surfaceControls[surfaceStats.surfaceControl],
+ surfaceStats.acquireTime, surfaceStats.previousReleaseFence,
+ surfaceStats.transformHint);
+ callbacksMap[callbackId]
+ .surfaceControls[surfaceStats.surfaceControl]
+ ->setTransformHint(surfaceStats.transformHint);
}
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
surfaceControlStats);
- mCallbacks.erase(callbackId);
}
}
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 6320556..f1758a2 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -27,6 +27,7 @@
#include <utils/RefBase.h>
#include <system/window.h>
+#include <thread>
namespace android {
@@ -50,7 +51,6 @@
void setNextTransaction(SurfaceComposerClient::Transaction *t);
void update(const sp<SurfaceControl>& surface, int width, int height);
-
virtual ~BLASTBufferQueue() = default;
@@ -61,32 +61,35 @@
BLASTBufferQueue& operator = (const BLASTBufferQueue& rhs);
BLASTBufferQueue(const BLASTBufferQueue& rhs);
- sp<SurfaceControl> mSurfaceControl;
-
- mutable std::mutex mMutex;
+ void processNextBufferLocked() REQUIRES(mMutex);
- static const int MAX_BUFFERS = 2;
+ sp<SurfaceControl> mSurfaceControl;
+
+ std::mutex mMutex;
+ std::condition_variable mCallbackCV;
+ uint64_t mPendingCallbacks GUARDED_BY(mMutex);
+
+ static const int MAX_BUFFERS = 3;
struct BufferInfo {
sp<GraphicBuffer> buffer;
int fence;
};
-
- int mDequeuedBuffers = 0;
- int mWidth;
- int mHeight;
+ std::queue<const BufferItem> mShadowQueue GUARDED_BY(mMutex);
+ bool mAcquired GUARDED_BY(mMutex);
- BufferItem mLastSubmittedBufferItem;
- BufferItem mNextCallbackBufferItem;
- sp<Fence> mLastFence;
+ int mWidth GUARDED_BY(mMutex);
+ int mHeight GUARDED_BY(mMutex);
- std::condition_variable mDequeueWaitCV;
+ BufferItem mLastSubmittedBufferItem GUARDED_BY(mMutex);
+ BufferItem mNextCallbackBufferItem GUARDED_BY(mMutex);
+ sp<Fence> mLastFence GUARDED_BY(mMutex);
sp<IGraphicBufferConsumer> mConsumer;
sp<IGraphicBufferProducer> mProducer;
sp<BufferItemConsumer> mBufferItemConsumer;
- SurfaceComposerClient::Transaction* mNextTransaction = nullptr;
+ SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex);
};
} // namespace android
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index ff22913..6ecdae5 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -19,6 +19,8 @@
#include <gui/BLASTBufferQueue.h>
#include <android/hardware/graphics/common/1.2/types.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/BufferQueueProducer.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
#include <gui/SurfaceComposerClient.h>
@@ -65,9 +67,11 @@
return mBlastBufferQueueAdapter->mSurfaceControl;
}
- void waitForCallback() {
+ void waitForCallbacks() {
std::unique_lock lock{mBlastBufferQueueAdapter->mMutex};
- mBlastBufferQueueAdapter->mDequeueWaitCV.wait_for(lock, 1s);
+ while (mBlastBufferQueueAdapter->mPendingCallbacks > 0) {
+ mBlastBufferQueueAdapter->mCallbackCV.wait(lock);
+ }
}
private:
@@ -116,6 +120,17 @@
.apply();
}
+ void setUpProducer(BLASTBufferQueueHelper adapter, sp<IGraphicBufferProducer>& producer) {
+ auto igbProducer = adapter.getIGraphicBufferProducer();
+ ASSERT_NE(nullptr, igbProducer.get());
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ ASSERT_EQ(NO_ERROR,
+ igbProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
+ &qbOutput));
+ ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
+ producer = igbProducer;
+ }
+
void fillBuffer(uint32_t* bufData, uint32_t width, uint32_t height, uint32_t stride, uint8_t r,
uint8_t g, uint8_t b) {
for (uint32_t row = 0; row < height; row++) {
@@ -195,14 +210,8 @@
uint8_t b = 0;
BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
- auto igbProducer = adapter.getIGraphicBufferProducer();
- ASSERT_NE(nullptr, igbProducer.get());
- IGraphicBufferProducer::QueueBufferOutput qbOutput;
- ASSERT_EQ(NO_ERROR,
- igbProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
- &qbOutput));
- ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(3));
- ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
int slot;
sp<Fence> fence;
@@ -219,6 +228,7 @@
fillBuffer(bufData, buf->getWidth(), buf->getHeight(), buf->getStride(), r, g, b);
buf->unlock();
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN,
Rect(mDisplayWidth, mDisplayHeight),
NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
@@ -226,7 +236,7 @@
igbProducer->queueBuffer(slot, input, &qbOutput);
ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
- adapter.waitForCallback();
+ sleep(1);
// capture screen and verify that it is red
bool capturedSecureLayers;
@@ -237,4 +247,43 @@
/*useIdentityTransform*/ false));
ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b));
}
+
+TEST_F(BLASTBufferQueueTest, TripleBuffering) {
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+
+ std::vector<std::pair<int, sp<Fence>>> allocated;
+ for (int i = 0; i < 3; i++) {
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
+ PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr);
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+ ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
+ allocated.push_back({slot, fence});
+ }
+ for (int i = 0; i < allocated.size(); i++) {
+ igbProducer->cancelBuffer(allocated[i].first, allocated[i].second);
+ }
+
+ for (int i = 0; i < 10; i++) {
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
+ PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr);
+ ASSERT_EQ(NO_ERROR, ret);
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ IGraphicBufferProducer::QueueBufferInput input(systemTime(), false, HAL_DATASPACE_UNKNOWN,
+ Rect(mDisplayWidth, mDisplayHeight),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
+ Fence::NO_FENCE);
+ igbProducer->queueBuffer(slot, input, &qbOutput);
+ }
+ adapter.waitForCallbacks();
+}
} // namespace android
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index aef7aed..103f775 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -543,7 +543,6 @@
// Should now be able to dequeue up to minBuffers times
DequeueBufferResult result;
for (int i = 0; i < minBuffers; ++i) {
-
EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
(dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
TEST_PRODUCER_USAGE_BITS, &result)))
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 8d1dd63..b7937dc 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -547,7 +547,7 @@
return UNKNOWN_ERROR;
}
*outSeq = msg.body.finished.seq;
- *outHandled = msg.body.finished.handled;
+ *outHandled = msg.body.finished.handled == 1;
return OK;
}
@@ -1065,7 +1065,7 @@
InputMessage msg;
msg.header.type = InputMessage::Type::FINISHED;
msg.body.finished.seq = seq;
- msg.body.finished.handled = handled;
+ msg.body.finished.handled = handled ? 1 : 0;
return mChannel->sendMessage(&msg);
}
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 8d8cf06..0fb6cfc 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -73,4 +73,20 @@
CHECK_OFFSET(InputMessage::Body::Finished, handled, 4);
}
+void TestHeaderSize() {
+ static_assert(sizeof(InputMessage::Header) == 8);
+}
+
+/**
+ * We cannot use the Body::size() method here because it is not static for
+ * the Motion type, where "pointerCount" variable affects the size and can change at runtime.
+ */
+void TestBodySize() {
+ static_assert(sizeof(InputMessage::Body::Key) == 64);
+ static_assert(sizeof(InputMessage::Body::Motion) ==
+ offsetof(InputMessage::Body::Motion, pointers) +
+ sizeof(InputMessage::Body::Motion::Pointer) * MAX_POINTERS);
+ static_assert(sizeof(InputMessage::Body::Finished) == 8);
+}
+
} // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index aba5a30..746908b 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -252,6 +252,10 @@
mDispatchEnabled(false),
mDispatchFrozen(false),
mInputFilterEnabled(false),
+ // mInTouchMode will be initialized by the WindowManager to the default device config.
+ // To avoid leaking stack in case that call never comes, and for tests,
+ // initialize it here anyways.
+ mInTouchMode(true),
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
mLooper = new Looper(false);
@@ -3538,6 +3542,11 @@
mLooper->wake();
}
+void InputDispatcher::setInTouchMode(bool inTouchMode) {
+ std::scoped_lock lock(mLock);
+ mInTouchMode = inTouchMode;
+}
+
bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
if (fromToken == toToken) {
if (DEBUG_FOCUS) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index d21b0a1..5d7d812 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -102,6 +102,7 @@
virtual void setFocusedDisplay(int32_t displayId) override;
virtual void setInputDispatchMode(bool enabled, bool frozen) override;
virtual void setInputFilterEnabled(bool enabled) override;
+ virtual void setInTouchMode(bool inTouchMode) override;
virtual bool transferTouchFocus(const sp<IBinder>& fromToken,
const sp<IBinder>& toToken) override;
@@ -247,6 +248,7 @@
bool mDispatchEnabled GUARDED_BY(mLock);
bool mDispatchFrozen GUARDED_BY(mLock);
bool mInputFilterEnabled GUARDED_BY(mLock);
+ bool mInTouchMode GUARDED_BY(mLock);
std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay
GUARDED_BY(mLock);
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 5acf92b..2e9bca2 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -93,21 +93,22 @@
sp<InputChannel> inputChannel;
// Flags for the input target.
- int32_t flags;
+ int32_t flags = 0;
// The x and y offset to add to a MotionEvent as it is delivered.
// (ignored for KeyEvents)
- float xOffset, yOffset;
+ float xOffset = 0.0f;
+ float yOffset = 0.0f;
// Scaling factor to apply to MotionEvent as it is delivered.
// (ignored for KeyEvents)
- float globalScaleFactor;
+ float globalScaleFactor = 1.0f;
float windowXScale = 1.0f;
float windowYScale = 1.0f;
// The subset of pointer ids to include in motion events dispatched to this input target
// if FLAG_SPLIT is set.
- BitSet32 pointerIds;
+ BitSet32 pointerIds{};
};
std::string dispatchModeToString(int32_t dispatchMode);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index ce7366f..3082738 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -116,6 +116,14 @@
*/
virtual void setInputFilterEnabled(bool enabled) = 0;
+ /**
+ * Set the touch mode state.
+ * Touch mode is a global state that apps may enter / exit based on specific
+ * user interactions with input devices.
+ * If true, the device is in touch mode.
+ */
+ virtual void setInTouchMode(bool inTouchMode) = 0;
+
/* Transfers touch focus from one window to another window.
*
* Returns true on success. False if the window did not actually have touch focus.