Merge "Add body sensors app op - framework native" into mnc-dev
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 7668a6c..95c49cf 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -99,6 +99,67 @@
closedir(d);
}
+static bool skip_not_stat(const char *path) {
+ static const char stat[] = "/stat";
+ size_t len = strlen(path);
+ if (path[len - 1] == '/') { /* Directory? */
+ return false;
+ }
+ return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
+}
+
+static const char mmcblk0[] = "/sys/block/mmcblk0/";
+
+static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
+ unsigned long fields[11], read_perf, write_perf;
+ bool z;
+ char *cp, *buffer = NULL;
+ size_t i = 0;
+ FILE *fp = fdopen(fd, "rb");
+ getline(&buffer, &i, fp);
+ fclose(fp);
+ if (!buffer) {
+ return -errno;
+ }
+ i = strlen(buffer);
+ while ((i > 0) && (buffer[i - 1] == '\n')) {
+ buffer[--i] = '\0';
+ }
+ if (!*buffer) {
+ free(buffer);
+ return 0;
+ }
+ z = true;
+ for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
+ fields[i] = strtol(cp, &cp, 0);
+ if (fields[i] != 0) {
+ z = false;
+ }
+ }
+ if (z) { /* never accessed */
+ free(buffer);
+ return 0;
+ }
+
+ if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
+ path += sizeof(mmcblk0) - 1;
+ }
+
+ printf("%s: %s\n", path, buffer);
+ free(buffer);
+
+ read_perf = 0;
+ if (fields[3]) {
+ read_perf = 512 * fields[2] / fields[3];
+ }
+ write_perf = 0;
+ if (fields[7]) {
+ write_perf = 512 * fields[6] / fields[7];
+ }
+ printf("%s: read: %luKB/s write: %luKB/s\n", path, read_perf, write_perf);
+ return 0;
+}
+
/* dumps the current system state to stdout */
static void dumpstate() {
time_t now = time(NULL);
@@ -133,7 +194,7 @@
dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
run_command("UPTIME", 10, "uptime", NULL);
- dump_file("MMC PERF", "/sys/block/mmcblk0/stat");
+ dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
dump_file("MEMORY INFO", "/proc/meminfo");
run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL);
run_command("PROCRANK", 20, "procrank", NULL);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 8335e26..c5d3044 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -35,6 +35,16 @@
*/
int dump_file_from_fd(const char *title, const char *path, int fd);
+/* calls skip to gate calling dump_from_fd recursively
+ * in the specified directory. dump_from_fd defaults to
+ * dump_file_from_fd above when set to NULL. skip defaults
+ * to false when set to NULL. dump_from_fd will always be
+ * called with title NULL.
+ */
+int dump_files(const char *title, const char *dir,
+ bool (*skip)(const char *path),
+ int (*dump_from_fd)(const char *title, const char *path, int fd));
+
/* forks a command and waits for it to finish -- terminate args with NULL */
int run_command(const char *title, int timeout_seconds, const char *command, ...);
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index 3d9a2b5..5801de1 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -310,6 +310,75 @@
return _dump_file_from_fd(title, path, fd);
}
+/* calls skip to gate calling dump_from_fd recursively
+ * in the specified directory. dump_from_fd defaults to
+ * dump_file_from_fd above when set to NULL. skip defaults
+ * to false when set to NULL. dump_from_fd will always be
+ * called with title NULL.
+ */
+int dump_files(const char *title, const char *dir,
+ bool (*skip)(const char *path),
+ int (*dump_from_fd)(const char *title, const char *path, int fd)) {
+ DIR *dirp;
+ struct dirent *d;
+ char *newpath = NULL;
+ char *slash = "/";
+ int fd, retval = 0;
+
+ if (title) {
+ printf("------ %s (%s) ------\n", title, dir);
+ }
+
+ if (dir[strlen(dir) - 1] == '/') {
+ ++slash;
+ }
+ dirp = opendir(dir);
+ if (dirp == NULL) {
+ retval = -errno;
+ fprintf(stderr, "%s: %s\n", dir, strerror(errno));
+ return retval;
+ }
+
+ if (!dump_from_fd) {
+ dump_from_fd = dump_file_from_fd;
+ }
+ for (; ((d = readdir(dirp))); free(newpath), newpath = NULL) {
+ if ((d->d_name[0] == '.')
+ && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
+ || (d->d_name[1] == '\0'))) {
+ continue;
+ }
+ asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
+ (d->d_type == DT_DIR) ? "/" : "");
+ if (!newpath) {
+ retval = -errno;
+ continue;
+ }
+ if (skip && (*skip)(newpath)) {
+ continue;
+ }
+ if (d->d_type == DT_DIR) {
+ int ret = dump_files(NULL, newpath, skip, dump_from_fd);
+ if (ret < 0) {
+ retval = ret;
+ }
+ continue;
+ }
+ fd = TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
+ if (fd < 0) {
+ retval = fd;
+ printf("*** %s: %s\n", newpath, strerror(errno));
+ continue;
+ }
+ (*dump_from_fd)(NULL, newpath, fd);
+ }
+ closedir(dirp);
+ if (title) {
+ printf("\n");
+ }
+ return retval;
+}
+
/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
* it's possible to avoid issues where opening the file itself can get
* stuck.
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index 9c91fc7..0f42613 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -148,6 +148,9 @@
// Retrieve the sideband buffer stream, if any.
virtual sp<NativeHandle> getSidebandStream() const;
+ // See IGraphicBufferConsumer::setShadowQueueSize
+ virtual void setShadowQueueSize(size_t size);
+
// dump our state in a String
virtual void dump(String8& result, const char* prefix) const;
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index e3624b7..a22015c 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -274,6 +274,13 @@
// mBufferAge tracks the age of the contents of the most recently dequeued
// buffer as the number of frames that have elapsed since it was last queued
uint64_t mBufferAge;
+
+ // mConsumerHasShadowQueue determines if acquireBuffer should be more
+ // cautious about dropping buffers so that it always returns a buffer that
+ // is represented in the consumer's shadow queue.
+ bool mConsumerHasShadowQueue;
+ size_t mConsumerShadowQueueSize;
+
}; // class BufferQueueCore
} // namespace android
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 8f31b55..0be09a2 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -248,6 +248,11 @@
// Retrieve the sideband buffer stream, if any.
virtual sp<NativeHandle> getSidebandStream() const = 0;
+ // setShadowQueueSize notifies the BufferQueue that the consumer is
+ // shadowing its queue and allows it to limit the number of buffers it is
+ // permitted to drop during acquire so as to not get out of sync.
+ virtual void setShadowQueueSize(size_t size) = 0;
+
// dump state into a string
virtual void dump(String8& result, const char* prefix) const = 0;
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index c7d5e00..2deef0e 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -89,7 +89,20 @@
// the timestamps are being auto-generated by Surface. If the app isn't
// generating timestamps explicitly, it probably doesn't want frames to
// be discarded based on them.
+ //
+ // If the consumer is shadowing our queue, we also make sure that we
+ // don't drop so many buffers that the consumer hasn't received the
+ // onFrameAvailable callback for the buffer it acquires. That is, we
+ // want the buffer we return to be in the consumer's shadow queue.
+ size_t droppableBuffers = mCore->mConsumerShadowQueueSize > 1 ?
+ mCore->mConsumerShadowQueueSize - 1 : 0;
while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
+ if (mCore->mConsumerHasShadowQueue && droppableBuffers == 0) {
+ BQ_LOGV("acquireBuffer: no droppable buffers in consumer's"
+ " shadow queue, continuing");
+ break;
+ }
+
// If entry[1] is timely, drop entry[0] (and repeat). We apply an
// additional criterion here: we only drop the earlier buffer if our
// desiredPresent falls within +/- 1 second of the expected present.
@@ -124,6 +137,7 @@
}
mCore->mQueue.erase(front);
front = mCore->mQueue.begin();
+ --droppableBuffers;
}
// See if the front buffer is due
@@ -537,6 +551,14 @@
return mCore->mSidebandStream;
}
+void BufferQueueConsumer::setShadowQueueSize(size_t size) {
+ ATRACE_CALL();
+ BQ_LOGV("setShadowQueueSize: %zu", size);
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mConsumerHasShadowQueue = true;
+ mCore->mConsumerShadowQueueSize = size;
+}
+
void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
mCore->dump(result, prefix);
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 887f2cb..d0f7afa 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -71,7 +71,9 @@
mIsAllocating(false),
mIsAllocatingCondition(),
mAllowAllocation(true),
- mBufferAge(0)
+ mBufferAge(0),
+ mConsumerHasShadowQueue(false),
+ mConsumerShadowQueueSize(0)
{
if (allocator == NULL) {
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index 6658ab1..480dfb6 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -52,6 +52,7 @@
SET_CONSUMER_USAGE_BITS,
SET_TRANSFORM_HINT,
GET_SIDEBAND_STREAM,
+ SET_SHADOW_QUEUE_SIZE,
DUMP,
};
@@ -269,6 +270,17 @@
return stream;
}
+ virtual void setShadowQueueSize(size_t size) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
+ data.writeInt64(static_cast<int64_t>(size));
+ status_t result = remote()->transact(SET_SHADOW_QUEUE_SIZE, data, &reply);
+ if (result != NO_ERROR) {
+ ALOGE("setShadowQueueSize failed (%d)", result);
+ return;
+ }
+ }
+
virtual void dump(String8& result, const char* prefix) const {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
@@ -423,6 +435,12 @@
}
return NO_ERROR;
}
+ case SET_SHADOW_QUEUE_SIZE: {
+ CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
+ size_t size = static_cast<size_t>(data.readInt64());
+ setShadowQueueSize(size);
+ return NO_ERROR;
+ }
case DUMP: {
CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
String8 result = data.readString8();
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2944c63..9fb94dd 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -127,6 +127,10 @@
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
+ // Set the shadow queue size to 0 to notify the BufferQueue that we are
+ // shadowing it
+ mSurfaceFlingerConsumer->setShadowQueueSize(0);
+
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
@@ -164,9 +168,10 @@
{ // Autolock scope
Mutex::Autolock lock(mQueueItemLock);
mQueueItems.push_back(item);
+ mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
+ android_atomic_inc(&mQueuedFrames);
}
- android_atomic_inc(&mQueuedFrames);
mFlinger->signalLayerUpdate();
}
@@ -1259,14 +1264,39 @@
// layer update so we check again at the next opportunity.
mFlinger->signalLayerUpdate();
return outDirtyRegion;
+ } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
+ // If the buffer has been rejected, remove it from the shadow queue
+ // and return early
+ Mutex::Autolock lock(mQueueItemLock);
+
+ // Update the BufferQueue with the new shadow queue size after
+ // dropping this item
+ mQueueItems.removeAt(0);
+ mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
+
+ android_atomic_dec(&mQueuedFrames);
+ return outDirtyRegion;
}
- // Remove this buffer from our internal queue tracker
{ // Autolock scope
+ auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+
Mutex::Autolock lock(mQueueItemLock);
+
+ // Remove any stale buffers that have been dropped during
+ // updateTexImage
+ while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+ mQueueItems.removeAt(0);
+ android_atomic_dec(&mQueuedFrames);
+ }
+
+ // Update the BufferQueue with our new shadow queue size, since we
+ // have removed at least one item
mQueueItems.removeAt(0);
+ mSurfaceFlingerConsumer->setShadowQueueSize(mQueueItems.size());
}
+
// Decrement the queued-frames count. Signal another event if we
// have more frames pending.
if (android_atomic_dec(&mQueuedFrames) > 1) {
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 19c497a..a9a2958 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -74,7 +74,7 @@
int buf = item.mBuf;
if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR);
- return NO_ERROR;
+ return BUFFER_REJECTED;
}
// Release the previous buffer.
@@ -125,6 +125,10 @@
return mConsumer->getSidebandStream();
}
+void SurfaceFlingerConsumer::setShadowQueueSize(size_t size) {
+ mConsumer->setShadowQueueSize(size);
+}
+
// We need to determine the time when a buffer acquired now will be
// displayed. This can be calculated:
// time when previous buffer's actual-present fence was signaled
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index 1aaba18..a90a8b9 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -28,6 +28,8 @@
*/
class SurfaceFlingerConsumer : public GLConsumer {
public:
+ static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
+
struct ContentsChangedListener: public FrameAvailableListener {
virtual void onSidebandStreamChanged() = 0;
};
@@ -68,6 +70,9 @@
sp<NativeHandle> getSidebandStream() const;
+ // See IGraphicBufferConsumer::setShadowQueueSize
+ void setShadowQueueSize(size_t size);
+
nsecs_t computeExpectedPresent(const DispSync& dispSync);
private: