Ensure history has pointer id of interest. am: c7dc3784a3
am: 2d46ae7854
Change-Id: I0f8eec4ae2c4b37bfb0268f0f3c1822c496461ce
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 9e77e8f..b3d628c 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -144,10 +144,12 @@
* Returns a vector of dump fds under |dir_path| with a given |file_prefix|.
* The returned vector is sorted by the mtimes of the dumps. If |limit_by_mtime|
* is set, the vector only contains files that were written in the last 30 minutes.
+ * If |limit_by_count| is set, the vector only contains the ten latest files.
*/
static std::vector<DumpData>* GetDumpFds(const std::string& dir_path,
const std::string& file_prefix,
- bool limit_by_mtime) {
+ bool limit_by_mtime,
+ bool limit_by_count = true) {
const time_t thirty_minutes_ago = ds.now_ - 60 * 30;
std::unique_ptr<std::vector<DumpData>> dump_data(new std::vector<DumpData>());
@@ -190,6 +192,10 @@
std::sort(dump_data->begin(), dump_data->end());
+ if (limit_by_count && dump_data->size() > 10) {
+ dump_data->erase(dump_data->begin() + 10, dump_data->end());
+ }
+
return dump_data.release();
}
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 630c1f3..443dce6 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -5,13 +5,13 @@
srcs: ["installd_utils_test.cpp"],
shared_libs: [
"libbase",
- "liblog",
"libutils",
"libcutils",
],
static_libs: [
- "libinstalld",
"libdiskusage",
+ "libinstalld",
+ "liblog",
],
}
@@ -23,14 +23,14 @@
"libbase",
"libbinder",
"libcutils",
- "liblog",
- "liblogwrap",
"libselinux",
"libutils",
],
static_libs: [
- "libinstalld",
"libdiskusage",
+ "libinstalld",
+ "liblog",
+ "liblogwrap",
],
}
@@ -42,13 +42,13 @@
"libbase",
"libbinder",
"libcutils",
- "liblog",
- "liblogwrap",
"libselinux",
"libutils",
],
static_libs: [
- "libinstalld",
"libdiskusage",
+ "libinstalld",
+ "liblog",
+ "liblogwrap",
],
}
diff --git a/include/android/sensor.h b/include/android/sensor.h
index a88733c..2db0ee7 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -197,7 +197,7 @@
* A sensor event.
*/
-/* NOTE: Must match hardware/sensors.h */
+/* NOTE: changes to these structs have to be backward compatible */
typedef struct ASensorVector {
union {
float v[3];
@@ -259,7 +259,7 @@
};
} AAdditionalInfoEvent;
-/* NOTE: Must match hardware/sensors.h */
+/* NOTE: changes to this struct has to be backward compatible */
typedef struct ASensorEvent {
int32_t version; /* sizeof(struct ASensorEvent) */
int32_t sensor;
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index 795f575..ffa1614 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -264,6 +264,40 @@
Movement mMovements[HISTORY_SIZE];
};
+class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy {
+public:
+ ImpulseVelocityTrackerStrategy();
+ virtual ~ImpulseVelocityTrackerStrategy();
+
+ virtual void clear();
+ virtual void clearPointers(BitSet32 idBits);
+ virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const VelocityTracker::Position* positions);
+ virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
+
+private:
+ // Sample horizon.
+ // We don't use too much history by default since we want to react to quick
+ // changes in direction.
+ static constexpr nsecs_t HORIZON = 100 * 1000000; // 100 ms
+
+ // Number of samples to keep.
+ static constexpr size_t HISTORY_SIZE = 20;
+
+ struct Movement {
+ nsecs_t eventTime;
+ BitSet32 idBits;
+ VelocityTracker::Position positions[MAX_POINTERS];
+
+ inline const VelocityTracker::Position& getPosition(uint32_t id) const {
+ return positions[idBits.getIndexOfBit(id)];
+ }
+ };
+
+ size_t mIndex;
+ Movement mMovements[HISTORY_SIZE];
+};
+
} // namespace android
#endif // _LIBINPUT_VELOCITY_TRACKER_H
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 3d36376..7aa7872 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -335,16 +335,25 @@
return OK;
}
- auto status = mSlots[slot].mFence->getStatus();
-
- if (status == Fence::Status::Invalid) {
- CB_LOGE("fence has invalid state");
+ // Check status of fences first because merging is expensive.
+ // Merging an invalid fence with any other fence results in an
+ // invalid fence.
+ auto currentStatus = mSlots[slot].mFence->getStatus();
+ if (currentStatus == Fence::Status::Invalid) {
+ CB_LOGE("Existing fence has invalid state");
return BAD_VALUE;
}
- if (status == Fence::Status::Signaled) {
+ auto incomingStatus = fence->getStatus();
+ if (incomingStatus == Fence::Status::Invalid) {
+ CB_LOGE("New fence has invalid state");
mSlots[slot].mFence = fence;
- } else { // status == Fence::Status::Unsignaled
+ return BAD_VALUE;
+ }
+
+ // If both fences are signaled or both are unsignaled, we need to merge
+ // them to get an accurate timestamp.
+ if (currentStatus == incomingStatus) {
char fenceName[32] = {};
snprintf(fenceName, 32, "%.28s:%d", mName.string(), slot);
sp<Fence> mergedFence = Fence::merge(
@@ -357,7 +366,17 @@
return BAD_VALUE;
}
mSlots[slot].mFence = mergedFence;
+ } else if (incomingStatus == Fence::Status::Unsignaled) {
+ // If one fence has signaled and the other hasn't, the unsignaled
+ // fence will approximately correspond with the correct timestamp.
+ // There's a small race if both fences signal at about the same time
+ // and their statuses are retrieved with unfortunate timing. However,
+ // by this point, they will have both signaled and only the timestamp
+ // will be slightly off; any dependencies after this point will
+ // already have been met.
+ mSlots[slot].mFence = fence;
}
+ // else if (currentStatus == Fence::Status::Unsignaled) is a no-op.
return OK;
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 9b06e63..573f685 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -45,6 +45,8 @@
output.writeInt32(overrideScalingMode);
output.writeStrongBinder(IInterface::asBinder(barrierGbp));
output.writeStrongBinder(relativeLayerHandle);
+ output.writeStrongBinder(parentHandleForChild);
+ output.writeStrongBinder(childHandle);
output.write(transparentRegion);
return NO_ERROR;
}
@@ -77,6 +79,8 @@
barrierGbp =
interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
relativeLayerHandle = input.readStrongBinder();
+ parentHandleForChild = input.readStrongBinder();
+ childHandle = input.readStrongBinder();
input.read(transparentRegion);
return NO_ERROR;
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 5b1c599..6c9d88b 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1509,6 +1509,12 @@
return NO_ERROR;
}
+android_dataspace_t Surface::getBuffersDataSpace() {
+ ALOGV("Surface::getBuffersDataSpace");
+ Mutex::Autolock lock(mMutex);
+ return mDataSpace;
+}
+
void Surface::freeAllBuffers() {
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
mSlots[i].buffer = 0;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7ae2672..b0ae7e0 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -176,6 +176,9 @@
status_t reparentChildren(const sp<SurfaceComposerClient>& client,
const sp<IBinder>& id,
const sp<IBinder>& newParentHandle);
+ status_t reparentChild(const sp<SurfaceComposerClient>& client,
+ const sp<IBinder>& id, const sp<IBinder>& newParentHandle,
+ const sp<IBinder>& childHandle);
status_t detachChildren(const sp<SurfaceComposerClient>& client,
const sp<IBinder>& id);
status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client,
@@ -493,6 +496,21 @@
return NO_ERROR;
}
+status_t Composer::reparentChild(const sp<SurfaceComposerClient>& client,
+ const sp<IBinder>& id,
+ const sp<IBinder>& newParentHandle,
+ const sp<IBinder>& childHandle) {
+ Mutex::Autolock lock(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s) {
+ return BAD_INDEX;
+ }
+ s->what |= layer_state_t::eReparentChild;
+ s->parentHandleForChild = newParentHandle;
+ s->childHandle = childHandle;
+ return NO_ERROR;
+}
+
status_t Composer::detachChildren(
const sp<SurfaceComposerClient>& client,
const sp<IBinder>& id) {
@@ -831,6 +849,11 @@
return getComposer().reparentChildren(this, id, newParentHandle);
}
+status_t SurfaceComposerClient::reparentChild(const sp<IBinder>& id,
+ const sp<IBinder>& newParentHandle, const sp<IBinder>& childHandle) {
+ return getComposer().reparentChild(this, id, newParentHandle, childHandle);
+}
+
status_t SurfaceComposerClient::detachChildren(const sp<IBinder>& id) {
return getComposer().detachChildren(this, id);
}
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 58bd273..b9c5ef9 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -191,6 +191,13 @@
return mClient->reparentChildren(mHandle, newParentHandle);
}
+status_t SurfaceControl::reparentChild(const sp<IBinder>& newParentHandle,
+ const sp<IBinder>& childHandle) {
+ status_t err = validate();
+ if (err < 0) return err;
+ return mClient->reparentChild(mHandle, newParentHandle, childHandle);
+}
+
status_t SurfaceControl::detachChildren() {
status_t err = validate();
if (err < 0) return err;
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 55dd6bf..3fe29d9 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -281,6 +281,8 @@
// detachNextBuffer, or attachBuffer call.
status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out);
+ android_dataspace_t getBuffersDataSpace();
+
protected:
enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 145c059..6e2cb83 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -161,6 +161,8 @@
const sp<Surface>& handle, uint64_t frameNumber);
status_t reparentChildren(const sp<IBinder>& id,
const sp<IBinder>& newParentHandle);
+ status_t reparentChild(const sp<IBinder>& id, const sp<IBinder>& newParentHandle,
+ const sp<IBinder>& childHandle);
status_t detachChildren(const sp<IBinder>& id);
status_t setOverrideScalingMode(const sp<IBinder>& id,
int32_t overrideScalingMode);
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index c15209d..d8b67ef 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -124,6 +124,12 @@
// Reparents all children of this layer to the new parent handle.
status_t reparentChildren(const sp<IBinder>& newParentHandle);
+ // Reparents a specified child from this layer to the new parent handle.
+ // The child, parent, and new parent must all have the same client.
+ // This can be used instead of reparentChildren if the caller wants to
+ // only re-parent specific children.
+ status_t reparentChild(const sp<IBinder>& newParentHandle, const sp<IBinder>& childHandle);
+
// Detaches all child surfaces (and their children recursively)
// from their SurfaceControl.
// The child SurfaceControl's will not throw exceptions or return errors,
diff --git a/libs/gui/include/private/gui/LayerState.h b/libs/gui/include/private/gui/LayerState.h
index 307c764..4f73e04 100644
--- a/libs/gui/include/private/gui/LayerState.h
+++ b/libs/gui/include/private/gui/LayerState.h
@@ -59,7 +59,8 @@
eGeometryAppliesWithResize = 0x00001000,
eReparentChildren = 0x00002000,
eDetachChildren = 0x00004000,
- eRelativeLayerChanged = 0x00008000
+ eRelativeLayerChanged = 0x00008000,
+ eReparentChild = 0x00010000
};
layer_state_t()
@@ -107,6 +108,9 @@
sp<IBinder> relativeLayerHandle;
+ sp<IBinder> parentHandleForChild;
+ sp<IBinder> childHandle;
+
// non POD must be last. see write/read
Region transparentRegion;
};
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 62acea3..a914408 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -141,6 +141,11 @@
}
VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
+ if (!strcmp("impulse", strategy)) {
+ // Physical model of pushing an object. Quality: VERY GOOD.
+ // Works with duplicate coordinates, unclean finger liftoff.
+ return new ImpulseVelocityTrackerStrategy();
+ }
if (!strcmp("lsq1", strategy)) {
// 1st order least squares. Quality: POOR.
// Frequently underfits the touch data especially when the finger accelerates
@@ -352,9 +357,6 @@
// --- LeastSquaresVelocityTrackerStrategy ---
-const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON;
-const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE;
-
LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(
uint32_t degree, Weighting weighting) :
mDegree(degree), mWeighting(weighting) {
@@ -863,10 +865,6 @@
// --- LegacyVelocityTrackerStrategy ---
-const nsecs_t LegacyVelocityTrackerStrategy::HORIZON;
-const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE;
-const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION;
-
LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {
clear();
}
@@ -979,4 +977,192 @@
return true;
}
+// --- ImpulseVelocityTrackerStrategy ---
+
+ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy() {
+ clear();
+}
+
+ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() {
+}
+
+void ImpulseVelocityTrackerStrategy::clear() {
+ mIndex = 0;
+ mMovements[0].idBits.clear();
+}
+
+void ImpulseVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
+ BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
+ mMovements[mIndex].idBits = remainingIdBits;
+}
+
+void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const VelocityTracker::Position* positions) {
+ if (++mIndex == HISTORY_SIZE) {
+ mIndex = 0;
+ }
+
+ Movement& movement = mMovements[mIndex];
+ movement.eventTime = eventTime;
+ movement.idBits = idBits;
+ uint32_t count = idBits.count();
+ for (uint32_t i = 0; i < count; i++) {
+ movement.positions[i] = positions[i];
+ }
+}
+
+/**
+ * Calculate the total impulse provided to the screen and the resulting velocity.
+ *
+ * The touchscreen is modeled as a physical object.
+ * Initial condition is discussed below, but for now suppose that v(t=0) = 0
+ *
+ * The kinetic energy of the object at the release is E=0.5*m*v^2
+ * Then vfinal = sqrt(2E/m). The goal is to calculate E.
+ *
+ * The kinetic energy at the release is equal to the total work done on the object by the finger.
+ * The total work W is the sum of all dW along the path.
+ *
+ * dW = F*dx, where dx is the piece of path traveled.
+ * Force is change of momentum over time, F = dp/dt = m dv/dt.
+ * Then substituting:
+ * dW = m (dv/dt) * dx = m * v * dv
+ *
+ * Summing along the path, we get:
+ * W = sum(dW) = sum(m * v * dv) = m * sum(v * dv)
+ * Since the mass stays constant, the equation for final velocity is:
+ * vfinal = sqrt(2*sum(v * dv))
+ *
+ * Here,
+ * dv : change of velocity = (v[i+1]-v[i])
+ * dx : change of distance = (x[i+1]-x[i])
+ * dt : change of time = (t[i+1]-t[i])
+ * v : instantaneous velocity = dx/dt
+ *
+ * The final formula is:
+ * vfinal = sqrt(2) * sqrt(sum((v[i]-v[i-1])*|v[i]|)) for all i
+ * The absolute value is needed to properly account for the sign. If the velocity over a
+ * particular segment descreases, then this indicates braking, which means that negative
+ * work was done. So for two positive, but decreasing, velocities, this contribution would be
+ * negative and will cause a smaller final velocity.
+ *
+ * Initial condition
+ * There are two ways to deal with initial condition:
+ * 1) Assume that v(0) = 0, which would mean that the screen is initially at rest.
+ * This is not entirely accurate. We are only taking the past X ms of touch data, where X is
+ * currently equal to 100. However, a touch event that created a fling probably lasted for longer
+ * than that, which would mean that the user has already been interacting with the touchscreen
+ * and it has probably already been moving.
+ * 2) Assume that the touchscreen has already been moving at a certain velocity, calculate this
+ * initial velocity and the equivalent energy, and start with this initial energy.
+ * Consider an example where we have the following data, consisting of 3 points:
+ * time: t0, t1, t2
+ * x : x0, x1, x2
+ * v : 0 , v1, v2
+ * Here is what will happen in each of these scenarios:
+ * 1) By directly applying the formula above with the v(0) = 0 boundary condition, we will get
+ * vfinal = sqrt(2*(|v1|*(v1-v0) + |v2|*(v2-v1))). This can be simplified since v0=0
+ * vfinal = sqrt(2*(|v1|*v1 + |v2|*(v2-v1))) = sqrt(2*(v1^2 + |v2|*(v2 - v1)))
+ * since velocity is a real number
+ * 2) If we treat the screen as already moving, then it must already have an energy (per mass)
+ * equal to 1/2*v1^2. Then the initial energy should be 1/2*v1*2, and only the second segment
+ * will contribute to the total kinetic energy (since we can effectively consider that v0=v1).
+ * This will give the following expression for the final velocity:
+ * vfinal = sqrt(2*(1/2*v1^2 + |v2|*(v2-v1)))
+ * This analysis can be generalized to an arbitrary number of samples.
+ *
+ *
+ * Comparing the two equations above, we see that the only mathematical difference
+ * is the factor of 1/2 in front of the first velocity term.
+ * This boundary condition would allow for the "proper" calculation of the case when all of the
+ * samples are equally spaced in time and distance, which should suggest a constant velocity.
+ *
+ * Note that approach 2) is sensitive to the proper ordering of the data in time, since
+ * the boundary condition must be applied to the oldest sample to be accurate.
+ */
+static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count) {
+ // The input should be in reversed time order (most recent sample at index i=0)
+ // t[i] is in nanoseconds, but due to FP arithmetic, convert to seconds inside this function
+ static constexpr float NANOS_PER_SECOND = 1E-9;
+ static constexpr float sqrt2 = 1.41421356237;
+
+ if (count < 2) {
+ return 0; // if 0 or 1 points, velocity is zero
+ }
+ if (t[1] > t[0]) { // Algorithm will still work, but not perfectly
+ ALOGE("Samples provided to calculateImpulseVelocity in the wrong order");
+ }
+ if (count == 2) { // if 2 points, basic linear calculation
+ if (t[1] == t[0]) {
+ ALOGE("Events have identical time stamps t=%" PRId64 ", setting velocity = 0", t[0]);
+ return 0;
+ }
+ return (x[1] - x[0]) / (NANOS_PER_SECOND * (t[1] - t[0]));
+ }
+ // Guaranteed to have at least 3 points here
+ float work = 0;
+ float vprev, vcurr; // v[i-1] and v[i], respectively
+ vprev = 0;
+ for (size_t i = count - 1; i > 0 ; i--) { // start with the oldest sample and go forward in time
+ if (t[i] == t[i-1]) {
+ ALOGE("Events have identical time stamps t=%" PRId64 ", skipping sample", t[i]);
+ continue;
+ }
+ vcurr = (x[i] - x[i-1]) / (NANOS_PER_SECOND * (t[i] - t[i-1]));
+ work += (vcurr - vprev) * fabsf(vcurr);
+ if (i == count - 1) {
+ work *= 0.5; // initial condition, case 2) above
+ }
+ vprev = vcurr;
+ }
+ return (work < 0 ? -1.0 : 1.0) * sqrtf(fabsf(work)) * sqrt2;
+}
+
+bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id,
+ VelocityTracker::Estimator* outEstimator) const {
+ outEstimator->clear();
+
+ // Iterate over movement samples in reverse time order and collect samples.
+ float x[HISTORY_SIZE];
+ float y[HISTORY_SIZE];
+ nsecs_t time[HISTORY_SIZE];
+ size_t m = 0; // number of points that will be used for fitting
+ size_t index = mIndex;
+ const Movement& newestMovement = mMovements[mIndex];
+ do {
+ const Movement& movement = mMovements[index];
+ if (!movement.idBits.hasBit(id)) {
+ break;
+ }
+
+ nsecs_t age = newestMovement.eventTime - movement.eventTime;
+ if (age > HORIZON) {
+ break;
+ }
+
+ const VelocityTracker::Position& position = movement.getPosition(id);
+ x[m] = position.x;
+ y[m] = position.y;
+ time[m] = movement.eventTime;
+ index = (index == 0 ? HISTORY_SIZE : index) - 1;
+ } while (++m < HISTORY_SIZE);
+
+ if (m == 0) {
+ return false; // no data
+ }
+ outEstimator->xCoeff[0] = 0;
+ outEstimator->yCoeff[0] = 0;
+ outEstimator->xCoeff[1] = calculateImpulseVelocity(time, x, m);
+ outEstimator->yCoeff[1] = calculateImpulseVelocity(time, y, m);
+ outEstimator->xCoeff[2] = 0;
+ outEstimator->yCoeff[2] = 0;
+ outEstimator->time = newestMovement.eventTime;
+ outEstimator->degree = 2; // similar results to 2nd degree fit
+ outEstimator->confidence = 1;
+#if DEBUG_STRATEGY
+ ALOGD("velocity: (%f, %f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]);
+#endif
+ return true;
+}
+
} // namespace android
diff --git a/libs/sensor/OWNERS b/libs/sensor/OWNERS
new file mode 100644
index 0000000..6a38a1f
--- /dev/null
+++ b/libs/sensor/OWNERS
@@ -0,0 +1,2 @@
+ashutoshj@google.com
+pengxu@google.com
diff --git a/services/sensorservice/OWNERS b/services/sensorservice/OWNERS
new file mode 100644
index 0000000..6a38a1f
--- /dev/null
+++ b/services/sensorservice/OWNERS
@@ -0,0 +1,2 @@
+ashutoshj@google.com
+pengxu@google.com
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 7d9b0b7..da3b275 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -223,8 +223,13 @@
}
void SensorDevice::autoDisable(void *ident, int handle) {
- Info& info( mActivationCount.editValueFor(handle) );
Mutex::Autolock _l(mLock);
+ ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+ if (activationIndex < 0) {
+ ALOGW("Handle %d cannot be found in activation record", handle);
+ return;
+ }
+ Info& info(mActivationCount.editValueAt(activationIndex));
info.removeBatchParamsForIdent(ident);
}
@@ -235,7 +240,12 @@
bool actuateHardware = false;
Mutex::Autolock _l(mLock);
- Info& info( mActivationCount.editValueFor(handle) );
+ ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+ if (activationIndex < 0) {
+ ALOGW("Handle %d cannot be found in activation record", handle);
+ return BAD_VALUE;
+ }
+ Info& info(mActivationCount.editValueAt(activationIndex));
ALOGD_IF(DEBUG_CONNECTIONS,
"SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu",
@@ -329,7 +339,12 @@
ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
Mutex::Autolock _l(mLock);
- Info& info(mActivationCount.editValueFor(handle));
+ ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+ if (activationIndex < 0) {
+ ALOGW("Handle %d cannot be found in activation record", handle);
+ return BAD_VALUE;
+ }
+ Info& info(mActivationCount.editValueAt(activationIndex));
if (info.batchParams.indexOfKey(ident) < 0) {
BatchParams params(samplingPeriodNs, maxBatchReportLatencyNs);
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 248ef53..0244c1b 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -28,6 +28,7 @@
#include <utils/RefBase.h>
#include <utils/Log.h>
+#include <ui/DebugUtils.h>
#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
@@ -617,6 +618,7 @@
void DisplayDevice::dump(String8& result) const {
const Transform& tr(mGlobalTransform);
+ ANativeWindow* const window = mNativeWindow.get();
EGLint redSize, greenSize, blueSize, alphaSize;
eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &redSize);
eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &greenSize);
@@ -626,9 +628,9 @@
result.appendFormat(" type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
"(%d:%d:%d:%d), orient=%2d (type=%08x), "
"flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
- mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight,
- mNativeWindow.get(), redSize, greenSize, blueSize, alphaSize, mOrientation,
- tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
+ mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
+ redSize, greenSize, blueSize, alphaSize, mOrientation, tr.getType(),
+ getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
mVisibleLayersSortedByZ.size());
result.appendFormat(" v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
"transform:[[%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f][%0.3f,%0.3f,%0.3f]]\n",
@@ -636,6 +638,9 @@
mFrame.left, mFrame.top, mFrame.right, mFrame.bottom, mScissor.left,
mScissor.top, mScissor.right, mScissor.bottom, tr[0][0], tr[1][0], tr[2][0],
tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
+ auto const surface = static_cast<Surface*>(window);
+ android_dataspace dataspace = surface->getBuffersDataSpace();
+ result.appendFormat(" dataspace: %s (%d)\n", dataspaceDetails(dataspace).c_str(), dataspace);
String8 surfaceDump;
mDisplaySurface->dumpAsString(surfaceDump);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e92565f..826b4a8 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2501,7 +2501,7 @@
const Layer::State& layerState(getDrawingState());
const HWCInfo& hwcInfo = mHwcLayers.at(hwcId);
- result.appendFormat(" %10u | ", layerState.z);
+ result.appendFormat(" %10d | ", layerState.z);
result.appendFormat("%10s | ",
to_string(getCompositionType(hwcId)).c_str());
const Rect& frame = hwcInfo.displayFrame;
@@ -2625,6 +2625,44 @@
return true;
}
+bool Layer::reparentChild(const sp<IBinder>& newParentHandle, const sp<IBinder>& childHandle) {
+ if (newParentHandle == nullptr || childHandle == nullptr) {
+ return false;
+ }
+
+ auto handle = static_cast<Handle*>(newParentHandle.get());
+ sp<Layer> newParent = handle->owner.promote();
+ if (newParent == nullptr) {
+ ALOGE("Unable to promote Layer handle");
+ return false;
+ }
+
+ handle = static_cast<Handle*>(childHandle.get());
+ sp<Layer> child = handle->owner.promote();
+ if (child == nullptr) {
+ ALOGE("Unable to promote child Layer handle");
+ return false;
+ }
+
+ if (mCurrentChildren.indexOf(child) < 0) {
+ ALOGE("Child layer is not child of current layer");
+ return false;
+ }
+
+ sp<Client> parentClient(mClientRef.promote());
+ sp<Client> childClient(child->mClientRef.promote());
+ sp<Client> newParentClient(newParent->mClientRef.promote());
+
+ if (parentClient != childClient || childClient != newParentClient) {
+ ALOGE("Current layer, child layer, and new parent layer must have the same client");
+ return false;
+ }
+
+ newParent->addChild(child);
+ mCurrentChildren.remove(child);
+ return true;
+}
+
bool Layer::detachChildren() {
traverseInZOrder(LayerVector::StateSet::Drawing, [this](Layer* child) {
if (child == this) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f7b82e4..f94833b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -241,6 +241,7 @@
bool setOverrideScalingMode(int32_t overrideScalingMode);
void setInfo(uint32_t type, uint32_t appId);
bool reparentChildren(const sp<IBinder>& layer);
+ bool reparentChild(const sp<IBinder>& newParentHandle, const sp<IBinder>& childHandle);
bool detachChildren();
// If we have received a new buffer this frame, we will pass its surface
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6a01f30..4b079d6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3103,6 +3103,13 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
+ // Always re-parent the children that explicitly requested to get
+ // re-parented before the general re-parent of all children.
+ if (what & layer_state_t::eReparentChild) {
+ if (layer->reparentChild(s.parentHandleForChild, s.childHandle)) {
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eReparentChildren) {
if (layer->reparentChildren(s.reparentHandle)) {
flags |= eTransactionNeeded|eTraversalNeeded;
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index a92e1f9..71aa52d 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2679,6 +2679,13 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
+ // Always re-parent the children that explicitly requested to get
+ // re-parented before the general re-parent of all children.
+ if (what & layer_state_t::eReparentChild) {
+ if (layer->reparentChild(s.parentHandleForChild, s.childHandle)) {
+ flags |= eTransactionNeeded|eTraversalNeeded;
+ }
+ }
if (what & layer_state_t::eReparentChildren) {
if (layer->reparentChildren(s.reparentHandle)) {
flags |= eTransactionNeeded|eTraversalNeeded;
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 4ce14f8..aef5a5f 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -1123,4 +1123,33 @@
fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
}
+TEST_F(ChildLayerTest, ReparentChild) {
+ SurfaceComposerClient::openGlobalTransaction();
+ mChild->show();
+ mChild->setPosition(10, 10);
+ mFGSurfaceControl->setPosition(64, 64);
+ SurfaceComposerClient::closeGlobalTransaction(true);
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+ mFGSurfaceControl->reparentChild(mBGSurfaceControl->getHandle(), mChild->getHandle());
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->expectFGColor(64, 64);
+ // In reparenting we should have exposed the entire foreground surface.
+ mCapture->expectFGColor(74, 74);
+ // And the child layer should now begin at 10, 10 (since the BG
+ // layer is at (0, 0)).
+ mCapture->expectBGColor(9, 9);
+ mCapture->expectChildColor(10, 10);
+ }
+}
+
}
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index 60916f3..d97ffa3 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -36,7 +36,6 @@
#include <thread>
constexpr Config NULL_DISPLAY_CONFIG = static_cast<Config>(0);
-constexpr Display DEFAULT_DISPLAY = static_cast<Display>(1);
using namespace sftest;
@@ -168,7 +167,7 @@
ALOGV("enableCallback");
mCallbacksOn = enable;
if (mCallbacksOn) {
- mClient->onHotplug(DEFAULT_DISPLAY, IComposerCallback::Connection::CONNECTED);
+ mClient->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
}
}
@@ -507,7 +506,7 @@
if (mSurfaceComposer != nullptr) {
mSurfaceComposer->injectVSync(timestamp);
} else {
- mClient->onVsync(DEFAULT_DISPLAY, timestamp);
+ mClient->onVsync(PRIMARY_DISPLAY, timestamp);
}
}
}
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
index 294abb2..2a5a8ad 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
@@ -19,6 +19,9 @@
#include "ComposerClient.h"
#include "RenderState.h"
+// Needed for display type/ID enums
+#include <hardware/hwcomposer_defs.h>
+
#include <utils/Condition.h>
#include <chrono>
@@ -40,6 +43,13 @@
namespace sftest {
+// NOTE: The ID's need to be exactly these. VR composer and parts of
+// the SurfaceFlinger assume the display IDs to have these values
+// despite the enum being documented as a display type.
+// TODO: Reference to actual documentation
+constexpr Display PRIMARY_DISPLAY = static_cast<Display>(HWC_DISPLAY_PRIMARY);
+constexpr Display EXTERNAL_DISPLAY = static_cast<Display>(HWC_DISPLAY_EXTERNAL);
+
class FakeComposerClient : public ComposerBase {
public:
FakeComposerClient();
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 8902ede..9ac3331 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -168,17 +168,15 @@
android::hardware::ProcessState::self()->startThreadPool();
android::ProcessState::self()->startThreadPool();
- EXPECT_CALL(*mMockComposer, getDisplayType(1, _))
+ EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
.WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
Return(Error::NONE)));
- // Seems to be doubled right now, once for display ID 1 and once for 0. This sounds fishy
- // but encoding that here exactly.
- EXPECT_CALL(*mMockComposer, getDisplayAttribute(1, 1, _, _))
- .Times(5)
- .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
- // TODO: Find out what code is generating the ID 0.
- EXPECT_CALL(*mMockComposer, getDisplayAttribute(0, 1, _, _))
- .Times(5)
+ // Primary display will be queried twice for all 5 attributes. One
+ // set of queries comes from the SurfaceFlinger proper an the
+ // other set from the VR composer.
+ // TODO: Is VR composer always present? Change to atLeast(5)?
+ EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _))
+ .Times(2 * 5)
.WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
startSurfaceFlinger();
@@ -207,31 +205,32 @@
TEST_F(DisplayTest, Hotplug) {
ALOGD("DisplayTest::Hotplug");
- EXPECT_CALL(*mMockComposer, getDisplayType(2, _))
+ EXPECT_CALL(*mMockComposer, getDisplayType(EXTERNAL_DISPLAY, _))
.Times(2)
.WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
Return(Error::NONE)));
// The attribute queries will get done twice. This is for defaults
- EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, _, _))
+ EXPECT_CALL(*mMockComposer, getDisplayAttribute(EXTERNAL_DISPLAY, 1, _, _))
.Times(2 * 3)
.WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
// ... and then special handling for dimensions. Specifying this
// rules later means that gmock will try them first, i.e.,
// ordering of width/height vs. the default implementation for
// other queries is significant.
- EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, IComposerClient::Attribute::WIDTH, _))
+ EXPECT_CALL(*mMockComposer,
+ getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::WIDTH, _))
.Times(2)
.WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE)));
- EXPECT_CALL(*mMockComposer, getDisplayAttribute(2, 1, IComposerClient::Attribute::HEIGHT, _))
+ EXPECT_CALL(*mMockComposer,
+ getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::HEIGHT, _))
.Times(2)
.WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE)));
// TODO: Width and height queries are not actually called. Display
// info returns dimensions 0x0 in display info. Why?
- mMockComposer->hotplugDisplay(static_cast<Display>(2),
- IComposerCallback::Connection::CONNECTED);
+ mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
{
sp<android::IBinder> display(
@@ -257,13 +256,11 @@
}
}
- mMockComposer->hotplugDisplay(static_cast<Display>(2),
- IComposerCallback::Connection::DISCONNECTED);
+ mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
mMockComposer->clearFrames();
- mMockComposer->hotplugDisplay(static_cast<Display>(2),
- IComposerCallback::Connection::CONNECTED);
+ mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
{
sp<android::IBinder> display(
@@ -288,8 +285,7 @@
ASSERT_EQ(NO_ERROR, surfaceControl->show());
}
}
- mMockComposer->hotplugDisplay(static_cast<Display>(2),
- IComposerCallback::Connection::DISCONNECTED);
+ mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
}
////////////////////////////////////////////////
@@ -664,7 +660,7 @@
{{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_H_ROT_90, {64, 64, 128, 128}},
{{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_V_ROT_90, {64, 64, 128, 128}}};
// clang-format on
- constexpr int TEST_COUNT = sizeof(MATRIX_TESTS)/sizeof(matrixTestData);
+ constexpr int TEST_COUNT = sizeof(MATRIX_TESTS) / sizeof(matrixTestData);
for (int i = 0; i < TEST_COUNT; i++) {
// TODO: How to leverage the HWC2 stringifiers?
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
index 1d3a1d3..9ff9a4f 100644
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
@@ -23,6 +23,7 @@
#include <gui/BufferItemConsumer.h>
#include <ui/GraphicBuffer.h>
+#include <android/hardware/graphics/common/1.0/types.h>
#include <math/vec4.h>
#include <GLES3/gl3.h>
@@ -31,6 +32,7 @@
#include "Hwc2TestLayers.h"
using namespace android;
+using android::hardware::graphics::common::V1_0::BufferUsage;
/* Returns a fence from egl */
typedef void (*FenceCallback)(int32_t fence, void* callbackArgs);
@@ -396,8 +398,9 @@
{
/* Create new graphic buffer with correct dimensions */
mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
- mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
- "hwc2_test_buffer");
+ mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
+
int ret = mGraphicBuffer->initCheck();
if (ret) {
return ret;
@@ -408,7 +411,8 @@
/* Locks the buffer for writing */
uint8_t* img;
- mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+ mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
+ (void**)(&img));
uint32_t stride = mGraphicBuffer->getStride();
@@ -469,8 +473,9 @@
{
/* Create new graphic buffer with correct dimensions */
mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
- mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
- "hwc2_test_buffer");
+ mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
+
int ret = mGraphicBuffer->initCheck();
if (ret) {
return ret;
@@ -480,7 +485,8 @@
}
uint8_t* img;
- mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+ mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
+ (void**)(&img));
uint32_t stride = mGraphicBuffer->getStride();
@@ -570,8 +576,8 @@
* (100x50) at the end of the transformation. */
if (transform & HWC_TRANSFORM_ROT_90) {
float tmp = xPos;
- xPos = -yPos * dfW / dfH;
- yPos = tmp * dfH / dfW;
+ xPos = yPos * dfW / dfH;
+ yPos = -tmp * dfH / dfW;
}
/* Change origin back to the top left corner of the