Merge "SF: Factor out expected present time computation"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 1416629..f4d94b7 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1989,12 +1989,12 @@
}
if (ds.options_->do_fb) {
- ds.screenshot_path_ = ds.GetPath(".png");
+ ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
}
ds.tmp_path_ = ds.GetPath(".tmp");
ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
- std::string destination = ds.options_->bugreport_fd.get() != -1
+ std::string destination = ds.CalledByApi()
? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
: ds.bugreport_internal_dir_.c_str();
MYLOGD(
@@ -2008,7 +2008,7 @@
ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
if (ds.options_->do_zip_file) {
- ds.path_ = ds.GetPath(".zip");
+ ds.path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
create_parent_dirs(ds.path_.c_str());
ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
@@ -2043,7 +2043,7 @@
MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
ds.name_ = name;
if (!ds.screenshot_path_.empty()) {
- std::string new_screenshot_path = ds.GetPath(".png");
+ std::string new_screenshot_path = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
new_screenshot_path.c_str(), strerror(errno));
@@ -2061,7 +2061,7 @@
} else {
do_text_file = false;
// If the user has changed the suffix, we need to change the zip file name.
- std::string new_path = ds.GetPath(".zip");
+ std::string new_path = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
if (ds.path_ != new_path) {
MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
if (rename(ds.path_.c_str(), new_path.c_str())) {
@@ -2716,6 +2716,10 @@
ds.consent_callback_->getResult() == UserConsentResult::DENIED;
}
+bool Dumpstate::CalledByApi() const {
+ return ds.options_->bugreport_fd.get() != -1 ? true : false;
+}
+
void Dumpstate::CleanupFiles() {
android::os::UnlinkAndLogOnError(tmp_path_);
android::os::UnlinkAndLogOnError(screenshot_path_);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index ae6a721..fe330df 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -341,6 +341,11 @@
bool IsUserConsentDenied() const;
/*
+ * Returns true if dumpstate is called by bugreporting API
+ */
+ bool CalledByApi() const;
+
+ /*
* Structure to hold options that determine the behavior of dumpstate.
*/
struct DumpOptions {
diff --git a/include/input/Input.h b/include/input/Input.h
index a976246..ad8c233 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -24,6 +24,7 @@
*/
#include <android/input.h>
+#include <math.h>
#include <stdint.h>
#include <utils/BitSet.h>
#include <utils/KeyedVector.h>
@@ -476,6 +477,8 @@
float getYCursorPosition() const;
+ static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); }
+
inline nsecs_t getDownTime() const { return mDownTime; }
inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; }
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index 28cb138..9080ce1 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -19,7 +19,11 @@
name: "libtimeinstate_test",
srcs: ["testtimeinstate.cpp"],
shared_libs: [
+ "libbase",
+ "libbpf",
+ "libbpf_android",
"libtimeinstate",
+ "libnetdutils",
],
cflags: [
"-Werror",
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 41cbde1..0e68e62 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "libtimeinstate"
#include "cputimeinstate.h"
+#include "timeinstate.h"
#include <dirent.h>
#include <errno.h>
@@ -38,23 +39,12 @@
#include <libbpf.h>
#include <log/log.h>
-#define BPF_FS_PATH "/sys/fs/bpf/"
-
using android::base::StringPrintf;
using android::base::unique_fd;
namespace android {
namespace bpf {
-struct time_key_t {
- uint32_t uid;
- uint32_t freq;
-};
-
-struct val_t {
- uint64_t ar[100];
-};
-
static std::mutex gInitializedMutex;
static bool gInitialized = false;
static uint32_t gNPolicies = 0;
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index d4b8738..6347de1 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -1,14 +1,24 @@
+#include "timeinstate.h"
+
+#include <sys/sysinfo.h>
+
#include <unordered_map>
#include <vector>
#include <gtest/gtest.h>
+#include <android-base/unique_fd.h>
+#include <bpf/BpfMap.h>
#include <cputimeinstate.h>
+#include <libbpf.h>
namespace android {
namespace bpf {
+static constexpr uint64_t NSEC_PER_SEC = 1000000000;
+static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365;
+
using std::vector;
TEST(TimeInStateTest, SingleUid) {
@@ -33,8 +43,95 @@
}
}
+TEST(TimeInStateTest, SingleAndAllUidConsistent) {
+ auto map = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map.has_value());
+ ASSERT_FALSE(map->empty());
+
+ for (const auto &kv : *map) {
+ uint32_t uid = kv.first;
+ auto times1 = kv.second;
+ auto times2 = getUidCpuFreqTimes(uid);
+ ASSERT_TRUE(times2.has_value());
+
+ ASSERT_EQ(times1.size(), times2->size());
+ for (uint32_t i = 0; i < times1.size(); ++i) {
+ ASSERT_EQ(times1[i].size(), (*times2)[i].size());
+ for (uint32_t j = 0; j < times1[i].size(); ++j) {
+ ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC);
+ }
+ }
+ }
+}
+
+void TestCheckDelta(uint64_t before, uint64_t after) {
+ // Times should never decrease
+ ASSERT_LE(before, after);
+ // UID can't have run for more than ~1s on each CPU
+ ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf());
+}
+
+TEST(TimeInStateTest, AllUidMonotonic) {
+ auto map1 = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map1.has_value());
+ sleep(1);
+ auto map2 = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map2.has_value());
+
+ for (const auto &kv : *map1) {
+ uint32_t uid = kv.first;
+ auto times = kv.second;
+ ASSERT_NE(map2->find(uid), map2->end());
+ for (uint32_t policy = 0; policy < times.size(); ++policy) {
+ for (uint32_t freqIdx = 0; freqIdx < times[policy].size(); ++freqIdx) {
+ auto before = times[policy][freqIdx];
+ auto after = (*map2)[uid][policy][freqIdx];
+ ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after));
+ }
+ }
+ }
+}
+
+TEST(TimeInStateTest, AllUidSanityCheck) {
+ auto map = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map.has_value());
+
+ bool foundLargeValue = false;
+ for (const auto &kv : *map) {
+ for (const auto &timeVec : kv.second) {
+ for (const auto &time : timeVec) {
+ ASSERT_LE(time, NSEC_PER_YEAR);
+ if (time > UINT32_MAX) foundLargeValue = true;
+ }
+ }
+ }
+ // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
+ // uint64_t as expected, we should have some times higher than that.
+ ASSERT_TRUE(foundLargeValue);
+}
+
TEST(TimeInStateTest, RemoveUid) {
- auto times = getUidCpuFreqTimes(0);
+ uint32_t uid = 0;
+ {
+ // Find an unused UID
+ auto times = getUidsCpuFreqTimes();
+ ASSERT_TRUE(times.has_value());
+ ASSERT_FALSE(times->empty());
+ for (const auto &kv : *times) uid = std::max(uid, kv.first);
+ ++uid;
+ }
+ {
+ // Add a map entry for our fake UID by copying a real map entry
+ android::base::unique_fd fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")};
+ ASSERT_GE(fd, 0);
+ time_key_t k;
+ ASSERT_FALSE(getFirstMapKey(fd, &k));
+ val_t val;
+ ASSERT_FALSE(findMapEntry(fd, &k, &val));
+ k.uid = uid;
+ ASSERT_FALSE(writeToMapEntry(fd, &k, &val, BPF_NOEXIST));
+ }
+ auto times = getUidCpuFreqTimes(uid);
ASSERT_TRUE(times.has_value());
ASSERT_FALSE(times->empty());
@@ -44,15 +141,12 @@
}
ASSERT_GT(sum, (uint64_t)0);
- ASSERT_TRUE(clearUidCpuFreqTimes(0));
+ ASSERT_TRUE(clearUidCpuFreqTimes(uid));
- auto times2 = getUidCpuFreqTimes(0);
- ASSERT_TRUE(times2.has_value());
- ASSERT_EQ(times2->size(), times->size());
- for (size_t i = 0; i < times->size(); ++i) {
- ASSERT_EQ((*times2)[i].size(), (*times)[i].size());
- for (size_t j = 0; j < (*times)[i].size(); ++j) ASSERT_LE((*times2)[i][j], (*times)[i][j]);
- }
+ auto allTimes = getUidsCpuFreqTimes();
+ ASSERT_TRUE(allTimes.has_value());
+ ASSERT_FALSE(allTimes->empty());
+ ASSERT_EQ(allTimes->find(uid), allTimes->end());
}
} // namespace bpf
diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h
new file mode 100644
index 0000000..cf66ae7
--- /dev/null
+++ b/libs/cputimeinstate/timeinstate.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#define BPF_FS_PATH "/sys/fs/bpf/"
+
+struct time_key_t {
+ uint32_t uid;
+ uint32_t freq;
+};
+
+struct val_t {
+ uint64_t ar[100];
+};
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index bf7991a..be58b85 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -169,12 +169,10 @@
}
status_t ComposerState::write(Parcel& output) const {
- output.writeStrongBinder(IInterface::asBinder(client));
return state.write(output);
}
status_t ComposerState::read(const Parcel& input) {
- client = interface_cast<ISurfaceComposerClient>(input.readStrongBinder());
return state.read(input);
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 16a4b35..e6b1beb 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -202,7 +202,8 @@
* 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>, IBinderHash> surfaceControls;
+ 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];
@@ -365,16 +366,16 @@
if (count > parcel->dataSize()) {
return BAD_VALUE;
}
- std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> composerStates;
+ std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> composerStates;
composerStates.reserve(count);
for (size_t i = 0; i < count; i++) {
- sp<SurfaceControl> surfaceControl = SurfaceControl::readFromParcel(parcel);
+ sp<IBinder> surfaceControlHandle = parcel->readStrongBinder();
ComposerState composerState;
if (composerState.read(*parcel) == BAD_VALUE) {
return BAD_VALUE;
}
- composerStates[surfaceControl] = composerState;
+ composerStates[surfaceControlHandle] = composerState;
}
InputWindowCommands inputWindowCommands;
@@ -408,8 +409,8 @@
}
parcel->writeUint32(static_cast<uint32_t>(mComposerStates.size()));
- for (auto const& [surfaceControl, composerState] : mComposerStates) {
- surfaceControl->writeToParcel(parcel);
+ for (auto const& [surfaceHandle, composerState] : mComposerStates) {
+ parcel->writeStrongBinder(surfaceHandle);
composerState.write(*parcel);
}
@@ -418,11 +419,11 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
- for (auto const& kv : other.mComposerStates) {
- if (mComposerStates.count(kv.first) == 0) {
- mComposerStates[kv.first] = kv.second;
+ for (auto const& [surfaceHandle, composerState] : other.mComposerStates) {
+ if (mComposerStates.count(surfaceHandle) == 0) {
+ mComposerStates[surfaceHandle] = composerState;
} else {
- mComposerStates[kv.first].state.merge(kv.second.state);
+ mComposerStates[surfaceHandle].state.merge(composerState.state);
}
}
@@ -466,14 +467,12 @@
mDesiredPresentTime = -1;
}
-void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle,
- const sp<ISurfaceComposerClient>& client) {
+void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
Vector<ComposerState> composerStates;
Vector<DisplayState> displayStates;
ComposerState s;
- s.client = client;
s.state.surface = handle;
s.state.what |= layer_state_t::eReparent;
s.state.parentHandleForChild = nullptr;
@@ -500,8 +499,8 @@
}
size_t count = 0;
- for (auto& [sc, cs] : mComposerStates) {
- layer_state_t* s = getLayerState(sc);
+ for (auto& [handle, cs] : mComposerStates) {
+ layer_state_t* s = getLayerState(handle);
if (!(s->what & layer_state_t::eBufferChanged)) {
continue;
}
@@ -640,16 +639,15 @@
mEarlyWakeup = true;
}
-layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
- if (mComposerStates.count(sc) == 0) {
+layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<IBinder>& handle) {
+ if (mComposerStates.count(handle) == 0) {
// we don't have it, add an initialized layer_state to our list
ComposerState s;
- s.client = sc->getClient()->mClient;
- s.state.surface = sc->getHandle();
- mComposerStates[sc] = s;
+ s.state.surface = handle;
+ mComposerStates[handle] = s;
}
- return &(mComposerStates[sc].state);
+ return &(mComposerStates[handle].state);
}
void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index b9defdd..071314f 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -65,8 +65,8 @@
{
// Avoid reparenting the server-side surface to null if we are not the owner of it,
// meaning that we retrieved it from another process.
- if (mClient != nullptr && mHandle != nullptr && mOwned) {
- SurfaceComposerClient::doDropReferenceTransaction(mHandle, mClient->getClient());
+ if (mHandle != nullptr && mOwned) {
+ SurfaceComposerClient::doDropReferenceTransaction(mHandle);
}
release();
}
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index f438eb3..cbd1c85 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -206,7 +206,6 @@
};
struct ComposerState {
- sp<ISurfaceComposerClient> client;
layer_state_t state;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
@@ -274,8 +273,6 @@
};
static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
- if (lhs.client < rhs.client) return -1;
- if (lhs.client > rhs.client) return 1;
if (lhs.state.surface < rhs.state.surface) return -1;
if (lhs.state.surface > rhs.state.surface) return 1;
return 0;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 4dda97f..22ab62d 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -163,8 +163,7 @@
* Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it
* to null), but without needing an sp<SurfaceControl> to avoid infinite ressurection.
*/
- static void doDropReferenceTransaction(const sp<IBinder>& handle,
- const sp<ISurfaceComposerClient>& client);
+ static void doDropReferenceTransaction(const sp<IBinder>& handle);
/**
* Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is
@@ -270,6 +269,12 @@
}
};
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& iBinder) const {
+ return std::hash<IBinder*>{}(iBinder.get());
+ }
+ };
+
struct TCLHash {
std::size_t operator()(const sp<ITransactionCompletedListener>& tcl) const {
return std::hash<IBinder*>{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr);
@@ -286,7 +291,7 @@
};
class Transaction : Parcelable {
- std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
+ std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates;
SortedVector<DisplayState > mDisplayStates;
std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
mListenerCallbacks;
@@ -314,7 +319,10 @@
InputWindowCommands mInputWindowCommands;
int mStatus = NO_ERROR;
- layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
+ layer_state_t* getLayerState(const sp<IBinder>& surfaceHandle);
+ layer_state_t* getLayerState(const sp<SurfaceControl>& sc) {
+ return getLayerState(sc->getHandle());
+ }
DisplayState& getDisplayState(const sp<IBinder>& token);
void cacheBuffers();
@@ -560,15 +568,10 @@
CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
- struct IBinderHash {
- std::size_t operator()(const sp<IBinder>& iBinder) const {
- return std::hash<IBinder*>{}(iBinder.get());
- }
- };
-
struct CallbackTranslation {
TransactionCompletedCallback callbackFunction;
- std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls;
+ std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash>
+ surfaceControls;
};
std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 3266b07..dc4978b 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "Input"
//#define LOG_NDEBUG 0
-#include <math.h>
#include <limits.h>
#include <input/Input.h>
@@ -434,7 +433,7 @@
transformPoint(matrix, 0, 0, &originX, &originY);
// Apply the transformation to cursor position.
- if (!isnan(mXCursorPosition) && !isnan(mYCursorPosition)) {
+ if (isValidCursorPosition(mXCursorPosition, mYCursorPosition)) {
float x = mXCursorPosition + oldXOffset;
float y = mYCursorPosition + oldYOffset;
transformPoint(matrix, x, y, &x, &y);
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index ec34f3e..b879de6 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -603,9 +603,13 @@
ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1);
}
- // Check cursor positions.
- ASSERT_NEAR(sinf(PI_180 * (90 + ROTATION)) * RADIUS, event.getXCursorPosition(), 0.001);
- ASSERT_NEAR(-cosf(PI_180 * (90 + ROTATION)) * RADIUS, event.getYCursorPosition(), 0.001);
+ // Check cursor positions. The original cursor position is at (3 + RADIUS, 2), where the center
+ // of the circle is (3, 2), so the cursor position is to the right of the center of the circle.
+ // The choice of triangular functions in this test defines the angle of rotation clockwise
+ // relative to the y-axis. Therefore the cursor position's angle is 90 degrees. Here we swap the
+ // triangular function so that we don't have to add the 90 degrees.
+ ASSERT_NEAR(cosf(PI_180 * ROTATION) * RADIUS, event.getXCursorPosition(), 0.001);
+ ASSERT_NEAR(sinf(PI_180 * ROTATION) * RADIUS, event.getYCursorPosition(), 0.001);
// Applying the transformation should preserve the raw X and Y of the first point.
ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index 086a324..d242677 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -575,10 +575,11 @@
float applyCornerRadius(vec2 cropCoords)
{
vec2 position = cropCoords - cropCenter;
- // Increase precision here so that a large corner radius doesn't
- // cause floating point error
- highp vec2 dist = abs(position) + vec2(cornerRadius) - cropCenter;
- float plane = length(max(dist, vec2(0.0)));
+ // Scale down the dist vector here, as otherwise large corner
+ // radii can cause floating point issues when computing the norm
+ vec2 dist = (abs(position) - cropCenter + vec2(cornerRadius)) / 16.0;
+ // Once we've found the norm, then scale back up.
+ float plane = length(max(dist, vec2(0.0))) * 16.0;
return 1.0 - clamp(plane - cornerRadius, 0.0, 1.0);
}
)__SHADER__";
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index dbb6ba6..7b8e0f8 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -59,9 +59,6 @@
cc_defaults {
name: "gpuservice_binary",
defaults: ["gpuservice_defaults"],
- whole_static_libs: [
- "libsigchain",
- ],
shared_libs: [
"libbinder",
"libcutils",
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index eb4e8f2..6c3a4a2 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -146,12 +146,11 @@
* which keys are currently down. Finally, the event hub keeps track of the capabilities of
* individual input devices, such as their class and the set of key codes that they support.
*/
-class EventHubInterface : public virtual RefBase {
-protected:
+class EventHubInterface {
+public:
EventHubInterface() { }
virtual ~EventHubInterface() { }
-public:
// Synthetic raw event type codes produced when devices are added or removed.
enum {
// Sent when a device is added.
@@ -319,7 +318,6 @@
virtual void dump(std::string& dump);
virtual void monitor();
-protected:
virtual ~EventHub();
private:
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index be13707..fb28d1b 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -253,9 +253,17 @@
}
}
-template<typename T, typename U>
-static T getValueByKey(std::unordered_map<U, T>& map, U key) {
- typename std::unordered_map<U, T>::const_iterator it = map.find(key);
+/**
+ * Find the entry in std::unordered_map by key, and return it.
+ * If the entry is not found, return a default constructed entry.
+ *
+ * Useful when the entries are vectors, since an empty vector will be returned
+ * if the entry is not found.
+ * Also useful when the entries are sp<>. If an entry is not found, nullptr is returned.
+ */
+template <typename T, typename U>
+static T getValueByKey(const std::unordered_map<U, T>& map, U key) {
+ auto it = map.find(key);
return it != map.end() ? it->second : T{};
}
@@ -2766,7 +2774,7 @@
", policyFlags=0x%x, "
"action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
"edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
- "mYCursorPosition=%f, downTime=%" PRId64,
+ "yCursorPosition=%f, downTime=%" PRId64,
args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
args->edgeFlags, args->xPrecision, args->yPrecision, arg->xCursorPosition,
@@ -3144,14 +3152,7 @@
std::vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(
int32_t displayId) const {
- std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>::const_iterator it =
- mWindowHandlesByDisplay.find(displayId);
- if(it != mWindowHandlesByDisplay.end()) {
- return it->second;
- }
-
- // Return an empty one if nothing found.
- return std::vector<sp<InputWindowHandle>>();
+ return getValueByKey(mWindowHandlesByDisplay, displayId);
}
sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
@@ -3193,6 +3194,63 @@
return mInputChannelsByToken.at(token);
}
+void InputDispatcher::updateWindowHandlesForDisplayLocked(
+ const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) {
+ if (inputWindowHandles.empty()) {
+ // Remove all handles on a display if there are no windows left.
+ mWindowHandlesByDisplay.erase(displayId);
+ return;
+ }
+
+ // Since we compare the pointer of input window handles across window updates, we need
+ // to make sure the handle object for the same window stays unchanged across updates.
+ const std::vector<sp<InputWindowHandle>>& oldHandles = getWindowHandlesLocked(displayId);
+ std::unordered_map<sp<IBinder>, sp<InputWindowHandle>, IBinderHash> oldHandlesByTokens;
+ for (const sp<InputWindowHandle>& handle : oldHandles) {
+ oldHandlesByTokens[handle->getToken()] = handle;
+ }
+
+ std::vector<sp<InputWindowHandle>> newHandles;
+ for (const sp<InputWindowHandle>& handle : inputWindowHandles) {
+ if (!handle->updateInfo()) {
+ // handle no longer valid
+ continue;
+ }
+
+ const InputWindowInfo* info = handle->getInfo();
+ if ((getInputChannelLocked(handle->getToken()) == nullptr &&
+ info->portalToDisplayId == ADISPLAY_ID_NONE)) {
+ const bool noInputChannel =
+ info->inputFeatures & InputWindowInfo::INPUT_FEATURE_NO_INPUT_CHANNEL;
+ const bool canReceiveInput =
+ !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_TOUCHABLE) ||
+ !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_FOCUSABLE);
+ if (canReceiveInput && !noInputChannel) {
+ ALOGE("Window handle %s has no registered input channel",
+ handle->getName().c_str());
+ }
+ continue;
+ }
+
+ if (info->displayId != displayId) {
+ ALOGE("Window %s updated by wrong display %d, should belong to display %d",
+ handle->getName().c_str(), displayId, info->displayId);
+ continue;
+ }
+
+ if (oldHandlesByTokens.find(handle->getToken()) != oldHandlesByTokens.end()) {
+ const sp<InputWindowHandle> oldHandle = oldHandlesByTokens.at(handle->getToken());
+ oldHandle->updateFrom(handle);
+ newHandles.push_back(oldHandle);
+ } else {
+ newHandles.push_back(handle);
+ }
+ }
+
+ // Insert or replace
+ mWindowHandlesByDisplay[displayId] = newHandles;
+}
+
/**
* Called from InputManagerService, update window handle list by displayId that can receive input.
* A window handle contains information about InputChannel, Touch Region, Types, Focused,...
@@ -3212,73 +3270,19 @@
const std::vector<sp<InputWindowHandle>> oldWindowHandles =
getWindowHandlesLocked(displayId);
+ updateWindowHandlesForDisplayLocked(inputWindowHandles, displayId);
+
sp<InputWindowHandle> newFocusedWindowHandle = nullptr;
bool foundHoveredWindow = false;
-
- if (inputWindowHandles.empty()) {
- // Remove all handles on a display if there are no windows left.
- mWindowHandlesByDisplay.erase(displayId);
- } else {
- // Since we compare the pointer of input window handles across window updates, we need
- // to make sure the handle object for the same window stays unchanged across updates.
- const std::vector<sp<InputWindowHandle>>& oldHandles =
- mWindowHandlesByDisplay[displayId];
- std::unordered_map<sp<IBinder>, sp<InputWindowHandle>, IBinderHash> oldHandlesByTokens;
- for (const sp<InputWindowHandle>& handle : oldHandles) {
- oldHandlesByTokens[handle->getToken()] = handle;
+ for (const sp<InputWindowHandle>& windowHandle : getWindowHandlesLocked(displayId)) {
+ // Set newFocusedWindowHandle to the top most focused window instead of the last one
+ if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus &&
+ windowHandle->getInfo()->visible) {
+ newFocusedWindowHandle = windowHandle;
}
-
- std::vector<sp<InputWindowHandle>> newHandles;
- for (const sp<InputWindowHandle>& handle : inputWindowHandles) {
- if (!handle->updateInfo()) {
- // handle no longer valid
- continue;
- }
- const InputWindowInfo* info = handle->getInfo();
-
- if ((getInputChannelLocked(handle->getToken()) == nullptr &&
- info->portalToDisplayId == ADISPLAY_ID_NONE)) {
- const bool noInputChannel =
- info->inputFeatures & InputWindowInfo::INPUT_FEATURE_NO_INPUT_CHANNEL;
- const bool canReceiveInput =
- !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_TOUCHABLE) ||
- !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_FOCUSABLE);
- if (canReceiveInput && !noInputChannel) {
- ALOGE("Window handle %s has no registered input channel",
- handle->getName().c_str());
- }
- continue;
- }
-
- if (info->displayId != displayId) {
- ALOGE("Window %s updated by wrong display %d, should belong to display %d",
- handle->getName().c_str(), displayId, info->displayId);
- continue;
- }
-
- if (oldHandlesByTokens.find(handle->getToken()) != oldHandlesByTokens.end()) {
- const sp<InputWindowHandle> oldHandle =
- oldHandlesByTokens.at(handle->getToken());
- oldHandle->updateFrom(handle);
- newHandles.push_back(oldHandle);
- } else {
- newHandles.push_back(handle);
- }
+ if (windowHandle == mLastHoverWindowHandle) {
+ foundHoveredWindow = true;
}
-
- for (const sp<InputWindowHandle>& windowHandle : newHandles) {
- // Set newFocusedWindowHandle to the top most focused window instead of the last one
- if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus
- && windowHandle->getInfo()->visible) {
- newFocusedWindowHandle = windowHandle;
- }
- if (windowHandle == mLastHoverWindowHandle) {
- foundHoveredWindow = true;
- }
- }
-
- // Insert or replace
- mWindowHandlesByDisplay[displayId] = newHandles;
}
if (!foundHoveredWindow) {
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 46dd9bd..c30a8d6 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -1055,6 +1055,13 @@
sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock);
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
+ /*
+ * Validate and update InputWindowHandles for a given display.
+ */
+ void updateWindowHandlesForDisplayLocked(
+ const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId)
+ REQUIRES(mLock);
+
// Focus tracking for keys, trackball, etc.
std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay
GUARDED_BY(mLock);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 2de5ffa..3e236a9 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -260,12 +260,17 @@
// --- InputReader ---
-InputReader::InputReader(const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- const sp<InputListenerInterface>& listener) :
- mContext(this), mEventHub(eventHub), mPolicy(policy),
- mNextSequenceNum(1), mGlobalMetaState(0), mGeneration(1),
- mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
+InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
+ const sp<InputListenerInterface>& listener)
+ : mContext(this),
+ mEventHub(eventHub),
+ mPolicy(policy),
+ mNextSequenceNum(1),
+ mGlobalMetaState(0),
+ mGeneration(1),
+ mDisableVirtualKeysTimeout(LLONG_MIN),
+ mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 0c08e7d..11ef934 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -114,9 +114,9 @@
*/
class InputReader : public InputReaderInterface {
public:
- InputReader(const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- const sp<InputListenerInterface>& listener);
+ InputReader(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
+ const sp<InputListenerInterface>& listener);
virtual ~InputReader();
virtual void dump(std::string& dump);
@@ -181,7 +181,10 @@
Condition mReaderIsAliveCondition;
- sp<EventHubInterface> mEventHub;
+ // This could be unique_ptr, but due to the way InputReader tests are written,
+ // it is made shared_ptr here. In the tests, an EventHub reference is retained by the test
+ // in parallel to passing it to the InputReader.
+ std::shared_ptr<EventHubInterface> mEventHub;
sp<InputReaderPolicyInterface> mPolicy;
sp<QueuedInputListener> mQueuedListener;
diff --git a/services/inputflinger/InputReaderFactory.cpp b/services/inputflinger/InputReaderFactory.cpp
index 3534f6b..072499b 100644
--- a/services/inputflinger/InputReaderFactory.cpp
+++ b/services/inputflinger/InputReaderFactory.cpp
@@ -22,7 +22,7 @@
sp<InputReaderInterface> createInputReader(
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) {
- return new InputReader(new EventHub(), policy, listener);
+ return new InputReader(std::make_unique<EventHub>(), policy, listener);
}
} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 541de99..d95ac96 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -325,14 +325,13 @@
List<RawEvent> mEvents;
std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
-protected:
+public:
virtual ~FakeEventHub() {
for (size_t i = 0; i < mDevices.size(); i++) {
delete mDevices.valueAt(i);
}
}
-public:
FakeEventHub() { }
void addDevice(int32_t deviceId, const std::string& name, uint32_t classes) {
@@ -760,7 +759,7 @@
// --- FakeInputReaderContext ---
class FakeInputReaderContext : public InputReaderContext {
- sp<EventHubInterface> mEventHub;
+ std::shared_ptr<EventHubInterface> mEventHub;
sp<InputReaderPolicyInterface> mPolicy;
sp<InputListenerInterface> mListener;
int32_t mGlobalMetaState;
@@ -769,12 +768,14 @@
uint32_t mNextSequenceNum;
public:
- FakeInputReaderContext(const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- const sp<InputListenerInterface>& listener) :
- mEventHub(eventHub), mPolicy(policy), mListener(listener),
- mGlobalMetaState(0), mNextSequenceNum(1) {
- }
+ FakeInputReaderContext(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
+ const sp<InputListenerInterface>& listener)
+ : mEventHub(eventHub),
+ mPolicy(policy),
+ mListener(listener),
+ mGlobalMetaState(0),
+ mNextSequenceNum(1) {}
virtual ~FakeInputReaderContext() { }
@@ -999,12 +1000,10 @@
InputDevice* mNextDevice;
public:
- InstrumentedInputReader(const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- const sp<InputListenerInterface>& listener) :
- InputReader(eventHub, policy, listener),
- mNextDevice(nullptr) {
- }
+ InstrumentedInputReader(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
+ const sp<InputListenerInterface>& listener)
+ : InputReader(eventHub, policy, listener), mNextDevice(nullptr) {}
virtual ~InstrumentedInputReader() {
if (mNextDevice) {
@@ -1232,11 +1231,11 @@
protected:
sp<TestInputListener> mFakeListener;
sp<FakeInputReaderPolicy> mFakePolicy;
- sp<FakeEventHub> mFakeEventHub;
+ std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<InstrumentedInputReader> mReader;
virtual void SetUp() {
- mFakeEventHub = new FakeEventHub();
+ mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new TestInputListener();
@@ -1248,7 +1247,6 @@
mFakeListener.clear();
mFakePolicy.clear();
- mFakeEventHub.clear();
}
void addDevice(int32_t deviceId, const std::string& name, uint32_t classes,
@@ -1575,7 +1573,7 @@
static const int32_t DEVICE_CONTROLLER_NUMBER;
static const uint32_t DEVICE_CLASSES;
- sp<FakeEventHub> mFakeEventHub;
+ std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
sp<TestInputListener> mFakeListener;
FakeInputReaderContext* mFakeContext;
@@ -1583,7 +1581,7 @@
InputDevice* mDevice;
virtual void SetUp() {
- mFakeEventHub = new FakeEventHub();
+ mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new TestInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
@@ -1601,7 +1599,6 @@
delete mFakeContext;
mFakeListener.clear();
mFakePolicy.clear();
- mFakeEventHub.clear();
}
};
@@ -1770,14 +1767,14 @@
static const int32_t DEVICE_CONTROLLER_NUMBER;
static const uint32_t DEVICE_CLASSES;
- sp<FakeEventHub> mFakeEventHub;
+ std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
sp<TestInputListener> mFakeListener;
FakeInputReaderContext* mFakeContext;
InputDevice* mDevice;
virtual void SetUp() {
- mFakeEventHub = new FakeEventHub();
+ mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new TestInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
@@ -1795,7 +1792,6 @@
delete mFakeContext;
mFakeListener.clear();
mFakePolicy.clear();
- mFakeEventHub.clear();
}
void addConfigurationProperty(const char* key, const char* value) {
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 6e953f4..965d8f4 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -187,9 +187,6 @@
cflags: [
"-DLOG_TAG=\"SurfaceFlinger\"",
],
- whole_static_libs: [
- "libsigchain",
- ],
shared_libs: [
"android.frameworks.displayservice@1.0",
"android.hardware.configstore-utils",
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 096cd1a..5e994b7 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -369,6 +369,15 @@
return mCurrentSurfaceDamage;
}
+void BufferLayerConsumer::mergeSurfaceDamage(const Region& damage) {
+ if (damage.bounds() == Rect::INVALID_RECT ||
+ mCurrentSurfaceDamage.bounds() == Rect::INVALID_RECT) {
+ mCurrentSurfaceDamage = Region::INVALID_REGION;
+ } else {
+ mCurrentSurfaceDamage |= damage;
+ }
+}
+
int BufferLayerConsumer::getCurrentApi() const {
Mutex::Autolock lock(mMutex);
return mCurrentApi;
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 144686c..8536f6b 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -140,6 +140,9 @@
// must be called from SF main thread
const Region& getSurfaceDamage() const;
+ // Merge the given damage region into the current damage region value.
+ void mergeSurfaceDamage(const Region& damage);
+
// getCurrentApi retrieves the API which queues the current buffer.
int getCurrentApi() const;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index fe9edfe..3758bec 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -313,6 +313,7 @@
// and return early
if (queuedBuffer) {
Mutex::Autolock lock(mQueueItemLock);
+ mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
mFlinger->mTimeStats->removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
mQueueItems.removeAt(0);
mQueuedFrames--;
@@ -348,6 +349,7 @@
// Remove any stale buffers that have been dropped during
// updateTexImage
while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+ mConsumer->mergeSurfaceDamage(mQueueItems[0].mSurfaceDamage);
mFlinger->mTimeStats->removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
mQueueItems.removeAt(0);
mQueuedFrames--;
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 0c94052..ad5eb33 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -64,7 +64,7 @@
DispSyncThread(const char* name, bool showTraceDetailedInfo)
: mName(name),
mStop(false),
- mModelLocked(false),
+ mModelLocked("DispSync:ModelLocked", false),
mPeriod(0),
mPhase(0),
mReferenceTime(0),
@@ -121,13 +121,11 @@
void lockModel() {
Mutex::Autolock lock(mMutex);
mModelLocked = true;
- ATRACE_INT("DispSync:ModelLocked", mModelLocked);
}
void unlockModel() {
Mutex::Autolock lock(mMutex);
mModelLocked = false;
- ATRACE_INT("DispSync:ModelLocked", mModelLocked);
}
virtual bool threadLoop() {
@@ -431,7 +429,7 @@
const char* const mName;
bool mStop;
- bool mModelLocked;
+ TracedOrdinal<bool> mModelLocked;
nsecs_t mPeriod;
nsecs_t mPhase;
@@ -454,15 +452,14 @@
class ZeroPhaseTracer : public DispSync::Callback {
public:
- ZeroPhaseTracer() : mParity(false) {}
+ ZeroPhaseTracer() : mParity("ZERO_PHASE_VSYNC", false) {}
virtual void onDispSyncEvent(nsecs_t /*when*/) {
mParity = !mParity;
- ATRACE_INT("ZERO_PHASE_VSYNC", mParity ? 1 : 0);
}
private:
- bool mParity;
+ TracedOrdinal<bool> mParity;
};
DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0) {
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 5faf46e..571c9ca 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -31,19 +31,16 @@
nsecs_t offsetThresholdForNextVsync, bool traceVsync,
const char* name)
: mName(name),
+ mValue(base::StringPrintf("VSYNC-%s", name), 0),
mTraceVsync(traceVsync),
mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
- mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)),
- mVsyncOffsetLabel(base::StringPrintf("VsyncOffset-%s", name)),
- mVsyncNegativeOffsetLabel(base::StringPrintf("VsyncNegativeOffset-%s", name)),
mDispSync(dispSync),
- mPhaseOffset(phaseOffset),
+ mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset),
mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {}
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
if (enable) {
- tracePhaseOffset();
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
static_cast<DispSync::Callback*>(this),
mLastCallbackTime);
@@ -83,7 +80,6 @@
}
mPhaseOffset = phaseOffset;
- tracePhaseOffset();
// If we're not enabled, we don't need to mess with the listeners
if (!mEnabled) {
@@ -106,7 +102,6 @@
if (mTraceVsync) {
mValue = (mValue + 1) % 2;
- ATRACE_INT(mVsyncEventLabel.c_str(), mValue);
}
if (callback != nullptr) {
@@ -114,14 +109,4 @@
}
}
-void DispSyncSource::tracePhaseOffset() {
- if (mPhaseOffset > 0) {
- ATRACE_INT(mVsyncOffsetLabel.c_str(), mPhaseOffset);
- ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), 0);
- } else {
- ATRACE_INT(mVsyncOffsetLabel.c_str(), 0);
- ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), -mPhaseOffset);
- }
-}
-
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 50560a5..740c8c4 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -20,6 +20,7 @@
#include "DispSync.h"
#include "EventThread.h"
+#include "TracedOrdinal.h"
namespace android {
@@ -39,16 +40,11 @@
// The following method is the implementation of the DispSync::Callback.
virtual void onDispSyncEvent(nsecs_t when);
- void tracePhaseOffset() REQUIRES(mVsyncMutex);
-
const char* const mName;
- int mValue = 0;
+ TracedOrdinal<int> mValue;
const bool mTraceVsync;
const std::string mVsyncOnLabel;
- const std::string mVsyncEventLabel;
- const std::string mVsyncOffsetLabel;
- const std::string mVsyncNegativeOffsetLabel;
nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0;
DispSync* mDispSync;
@@ -57,7 +53,7 @@
VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr;
std::mutex mVsyncMutex;
- nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex);
+ TracedOrdinal<nsecs_t> mPhaseOffset GUARDED_BY(mVsyncMutex);
const nsecs_t mOffsetThresholdForNextVsync;
bool mEnabled GUARDED_BY(mVsyncMutex) = false;
};
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cd80f2b..5ac396e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -976,7 +976,6 @@
mPhaseOffsets->getOffsetThresholdForNextVsync());
}
mDesiredActiveConfigChanged = true;
- ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
if (mRefreshRateOverlay) {
mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
@@ -1021,7 +1020,6 @@
std::lock_guard<std::mutex> lock(mActiveConfigLock);
mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
mDesiredActiveConfigChanged = false;
- ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
@@ -1713,12 +1711,12 @@
// seeing this same value.
populateExpectedPresentTime();
- bool frameMissed = previousFrameMissed();
- bool hwcFrameMissed = mHadDeviceComposition && frameMissed;
- bool gpuFrameMissed = mHadClientComposition && frameMissed;
- ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
- ATRACE_INT("HwcFrameMissed", static_cast<int>(hwcFrameMissed));
- ATRACE_INT("GpuFrameMissed", static_cast<int>(gpuFrameMissed));
+ const TracedOrdinal<bool> frameMissed = {"FrameMissed", previousFrameMissed()};
+ const TracedOrdinal<bool> hwcFrameMissed = {"HwcFrameMissed",
+ mHadDeviceComposition && frameMissed};
+ const TracedOrdinal<bool> gpuFrameMissed = {"GpuFrameMissed",
+ mHadClientComposition && frameMissed};
+
if (frameMissed) {
mFrameMissedCount++;
mTimeStats->incrementMissedFrames();
@@ -3405,8 +3403,9 @@
const Region bounds(displayState.bounds);
const DisplayRenderArea renderArea(displayDevice);
- const bool hasClientComposition = getHwComposer().hasClientComposition(displayId);
- ATRACE_INT("hasClientComposition", hasClientComposition);
+ const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
+ getHwComposer().hasClientComposition(
+ displayId)};
bool applyColorMatrix = false;
@@ -3689,27 +3688,6 @@
return !mTransactionQueues.empty();
}
-bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>& states) {
- for (const ComposerState& state : states) {
- // Here we need to check that the interface we're given is indeed
- // one of our own. A malicious client could give us a nullptr
- // IInterface, or one of its own or even one of our own but a
- // different type. All these situations would cause us to crash.
- if (state.client == nullptr) {
- return true;
- }
-
- sp<IBinder> binder = IInterface::asBinder(state.client);
- if (binder == nullptr) {
- return true;
- }
-
- if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) == nullptr) {
- return true;
- }
- }
- return false;
-}
bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
bool useCachedExpectedPresentTime,
@@ -3752,10 +3730,6 @@
Mutex::Autolock _l(mStateLock);
- if (containsAnyInvalidClientState(states)) {
- return;
- }
-
// If its TransactionQueue already has a pending TransactionState or if it is pending
auto itr = mTransactionQueues.find(applyToken);
// if this is an animation frame, wait until prior animation frame has
@@ -3969,9 +3943,8 @@
const std::vector<ListenerCallbacks>& listenerCallbacks, int64_t postTime,
bool privileged) {
const layer_state_t& s = composerState.state;
- sp<Client> client(static_cast<Client*>(composerState.client.get()));
- sp<Layer> layer(client->getLayerUser(s.surface));
+ sp<Layer> layer(fromHandle(s.surface));
if (layer == nullptr) {
for (auto& listenerCallback : listenerCallbacks) {
mTransactionCompletedThread.registerUnpresentedCallbackHandle(
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 099ba72..9e5019d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -60,6 +60,7 @@
#include "Scheduler/VSyncModulator.h"
#include "SurfaceFlingerFactory.h"
#include "SurfaceTracing.h"
+#include "TracedOrdinal.h"
#include "TransactionCompletedThread.h"
#include <atomic>
@@ -578,7 +579,6 @@
void latchAndReleaseBuffer(const sp<Layer>& layer);
void commitTransaction() REQUIRES(mStateLock);
void commitOffscreenLayers();
- bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
bool useCachedExpectedPresentTime,
const Vector<ComposerState>& states);
@@ -1149,7 +1149,8 @@
ActiveConfigInfo mDesiredActiveConfig GUARDED_BY(mActiveConfigLock);
// below flags are set by main thread only
- bool mDesiredActiveConfigChanged GUARDED_BY(mActiveConfigLock) = false;
+ TracedOrdinal<bool> mDesiredActiveConfigChanged
+ GUARDED_BY(mActiveConfigLock) = {"DesiredActiveConfigChanged", false};
bool mCheckPendingFence = false;
bool mLumaSampling = true;
diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h
new file mode 100644
index 0000000..fb0f02e
--- /dev/null
+++ b/services/surfaceflinger/TracedOrdinal.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+#include <android-base/stringprintf.h>
+#include <utils/Trace.h>
+#include <cmath>
+#include <string>
+
+template <typename T>
+class TracedOrdinal {
+public:
+ static_assert(std::is_same<bool, T>() || (std::is_signed<T>() && std::is_integral<T>()),
+ "Type is not supported. Please test it with systrace before adding "
+ "it to the list.");
+
+ TracedOrdinal(std::string name, T initialValue)
+ : mName(name),
+ mNameNegative(android::base::StringPrintf("%sNegative", name.c_str())),
+ mHasGoneNegative(std::signbit(initialValue)),
+ mData(initialValue) {
+ trace();
+ }
+
+ operator T() const { return mData; }
+
+ TracedOrdinal& operator=(T other) {
+ mData = other;
+ mHasGoneNegative = mHasGoneNegative || std::signbit(mData);
+ trace();
+ return *this;
+ }
+
+private:
+ void trace() {
+ if (!std::signbit(mData)) {
+ ATRACE_INT64(mName.c_str(), int64_t(mData));
+ if (mHasGoneNegative) {
+ ATRACE_INT64(mNameNegative.c_str(), 0);
+ }
+ } else {
+ ATRACE_INT64(mNameNegative.c_str(), -int64_t(mData));
+ ATRACE_INT64(mName.c_str(), 0);
+ }
+ }
+
+ const std::string mName;
+ const std::string mNameNegative;
+ bool mHasGoneNegative;
+ T mData;
+};
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index aed7b40..c8f5618 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -28,6 +28,7 @@
#include <binder/ProcessState.h>
#include <gui/BufferItemConsumer.h>
+#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <gui/Surface.h>
@@ -6083,4 +6084,97 @@
}
}
+// This test ensures that when we drop an app buffer in SurfaceFlinger, we merge
+// the dropped buffer's damage region into the next buffer's damage region. If
+// we don't do this, we'll report an incorrect damage region to hardware
+// composer, resulting in broken rendering. This test checks the BufferQueue
+// case.
+//
+// Unfortunately, we don't currently have a way to inspect the damage region
+// SurfaceFlinger sends to hardware composer from a test, so this test requires
+// the dev to manually watch the device's screen during the test to spot broken
+// rendering. Because the results can't be automatically verified, this test is
+// marked disabled.
+TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDroppingBuffers) {
+ const int width = mDisplayWidth;
+ const int height = mDisplayHeight;
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
+ const auto producer = layer->getIGraphicBufferProducer();
+ const sp<IProducerListener> dummyListener(new DummyProducerListener);
+ IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
+ ASSERT_EQ(OK,
+ producer->connect(dummyListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
+
+ std::map<int, sp<GraphicBuffer>> slotMap;
+ auto slotToBuffer = [&](int slot, sp<GraphicBuffer>* buf) {
+ ASSERT_NE(nullptr, buf);
+ const auto iter = slotMap.find(slot);
+ ASSERT_NE(slotMap.end(), iter);
+ *buf = iter->second;
+ };
+
+ auto dequeue = [&](int* outSlot) {
+ ASSERT_NE(nullptr, outSlot);
+ *outSlot = -1;
+ int slot;
+ sp<Fence> fence;
+ uint64_t age;
+ FrameEventHistoryDelta timestamps;
+ const status_t dequeueResult =
+ producer->dequeueBuffer(&slot, &fence, width, height, PIXEL_FORMAT_RGBA_8888,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ &age, ×tamps);
+ if (dequeueResult == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+ sp<GraphicBuffer> newBuf;
+ ASSERT_EQ(OK, producer->requestBuffer(slot, &newBuf));
+ ASSERT_NE(nullptr, newBuf.get());
+ slotMap[slot] = newBuf;
+ } else {
+ ASSERT_EQ(OK, dequeueResult);
+ }
+ *outSlot = slot;
+ };
+
+ auto queue = [&](int slot, const Region& damage, nsecs_t displayTime) {
+ IGraphicBufferProducer::QueueBufferInput input(
+ /*timestamp=*/displayTime, /*isAutoTimestamp=*/false, HAL_DATASPACE_UNKNOWN,
+ /*crop=*/Rect::EMPTY_RECT, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
+ /*transform=*/0, Fence::NO_FENCE);
+ input.setSurfaceDamage(damage);
+ IGraphicBufferProducer::QueueBufferOutput output;
+ ASSERT_EQ(OK, producer->queueBuffer(slot, input, &output));
+ };
+
+ auto fillAndPostBuffers = [&](const Color& color) {
+ int slot1;
+ ASSERT_NO_FATAL_FAILURE(dequeue(&slot1));
+ int slot2;
+ ASSERT_NO_FATAL_FAILURE(dequeue(&slot2));
+
+ sp<GraphicBuffer> buf1;
+ ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot1, &buf1));
+ sp<GraphicBuffer> buf2;
+ ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot2, &buf2));
+ fillGraphicBufferColor(buf1, Rect(width, height), color);
+ fillGraphicBufferColor(buf2, Rect(width, height), color);
+
+ const auto displayTime = systemTime() + milliseconds_to_nanoseconds(100);
+ ASSERT_NO_FATAL_FAILURE(queue(slot1, Region::INVALID_REGION, displayTime));
+ ASSERT_NO_FATAL_FAILURE(
+ queue(slot2, Region(Rect(width / 3, height / 3, 2 * width / 3, 2 * height / 3)),
+ displayTime));
+ };
+
+ const auto startTime = systemTime();
+ const std::array<Color, 3> colors = {Color::RED, Color::GREEN, Color::BLUE};
+ int colorIndex = 0;
+ while (nanoseconds_to_seconds(systemTime() - startTime) < 10) {
+ ASSERT_NO_FATAL_FAILURE(fillAndPostBuffers(colors[colorIndex++ % colors.size()]));
+ std::this_thread::sleep_for(1s);
+ }
+
+ ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/version-script32.txt b/services/surfaceflinger/version-script32.txt
deleted file mode 100644
index 2340785..0000000
--- a/services/surfaceflinger/version-script32.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-global:
- EnsureFrontOfChain;
- AddSpecialSignalHandlerFn;
- RemoveSpecialSignalHandlerFn;
- bsd_signal;
- sigaction;
- signal;
- sigprocmask;
-local:
- *;
-};
diff --git a/services/surfaceflinger/version-script64.txt b/services/surfaceflinger/version-script64.txt
deleted file mode 100644
index acf3630..0000000
--- a/services/surfaceflinger/version-script64.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-global:
- EnsureFrontOfChain;
- AddSpecialSignalHandlerFn;
- RemoveSpecialSignalHandlerFn;
- sigaction;
- signal;
- sigprocmask;
-local:
- *;
-};