Merge "Added --skip option to skip services."
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 054db74..22fd2c3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -368,6 +368,10 @@
/* adds a new entry to the existing zip file. */
static bool add_zip_entry_from_fd(const std::string& entry_name, int fd) {
+ if (!zip_writer) {
+ ALOGD("Not adding zip entry %s from fd because zip_writer is not set", entry_name.c_str());
+ return false;
+ }
ALOGD("Adding zip entry %s", entry_name.c_str());
int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(),
ZipWriter::kCompress, get_mtime(fd, now));
@@ -420,14 +424,21 @@
/* adds all files from a directory to the zipped bugreport file */
void add_dir(const char *dir, bool recursive) {
- if (!zip_writer) return;
+ if (!zip_writer) {
+ ALOGD("Not adding dir %s because zip_writer is not set", dir);
+ return;
+ }
DurationReporter duration_reporter(dir, NULL);
dump_files(NULL, dir, recursive ? skip_none : is_dir, _add_file_from_fd);
}
/* adds a text entry entry to the existing zip file. */
static bool add_text_zip_entry(const std::string& entry_name, const std::string& content) {
- ALOGD("Adding zip text entry %s (%s)", entry_name.c_str(), content.c_str());
+ if (!zip_writer) {
+ ALOGD("Not adding text zip entry %s because zip_writer is not set", entry_name.c_str());
+ return false;
+ }
+ ALOGD("Adding zip text entry %s", entry_name.c_str());
int32_t err = zip_writer->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, now);
if (err) {
ALOGE("zip_writer->StartEntryWithTime(%s): %s\n", entry_name.c_str(),
@@ -772,7 +783,7 @@
" -s: write output to control socket (for init)\n"
" -q: disable vibrate\n"
" -B: send broadcast when finished (requires -o)\n"
- " -P: send broadacast when started and update system properties on progress (requires -o and -B)\n"
+ " -P: send broadcast when started and update system properties on progress (requires -o and -B)\n"
" -R: take bugreport in remote mode (requires -o, -z, -d and -B, shouldn't be used with -P)\n"
" -V: sets the bugreport format version (%s or %s)\n",
VERSION_DEFAULT.c_str(), VERSION_DUMPSYS_SPLIT.c_str());
@@ -794,6 +805,7 @@
}
if (!add_text_zip_entry("main_entry.txt", bugreport_name)) {
ALOGE("Failed to add main_entry.txt to .zip file\n");
+ return false;
}
int32_t err = zip_writer->Finish();
@@ -1027,6 +1039,7 @@
if (do_zip_file) {
ALOGD("Creating initial .zip file");
path = bugreport_dir + "/" + base_name + "-" + suffix + ".zip";
+ create_parent_dirs(path.c_str());
zip_file.reset(fopen(path.c_str(), "wb"));
if (!zip_file) {
ALOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 8332d22..a6afbf4 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -112,6 +112,9 @@
/* redirect output to a file */
void redirect_to_file(FILE *redirect, char *path);
+/* create leading directories, if necessary */
+void create_parent_dirs(const char *path);
+
/* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
const char *dump_traces();
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index ee60f57..0c35430 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -657,23 +657,35 @@
close(fd);
}
-/* redirect output to a file */
-void redirect_to_file(FILE *redirect, char *path) {
- char *chp = path;
+void create_parent_dirs(const char *path) {
+ char *chp = (char*) path;
/* skip initial slash */
if (chp[0] == '/')
chp++;
/* create leading directories, if necessary */
+ struct stat dir_stat;
while (chp && chp[0]) {
chp = strchr(chp, '/');
if (chp) {
*chp = 0;
- mkdir(path, 0770); /* drwxrwx--- */
+ if (stat(path, &dir_stat) == -1 || !S_ISDIR(dir_stat.st_mode)) {
+ ALOGI("Creating directory %s\n", path);
+ if (mkdir(path, 0770)) { /* drwxrwx--- */
+ ALOGE("Unable to create directory %s: %s\n", path, strerror(errno));
+ } else if (chown(path, AID_SHELL, AID_SHELL)) {
+ ALOGE("Unable to change ownership of dir %s: %s\n", path, strerror(errno));
+ }
+ }
*chp++ = '/';
}
}
+}
+
+/* redirect output to a file */
+void redirect_to_file(FILE *redirect, char *path) {
+ create_parent_dirs(path);
int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index cfe5a62..e9ec3d3 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -666,6 +666,14 @@
bool generate_debug_info = check_boolean_property("debug.generate-debug-info");
+ char app_image_format[kPropertyValueMax];
+ char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
+ bool have_app_image_format =
+ image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+ if (have_app_image_format) {
+ sprintf(image_format_arg, "--image-format=%s", app_image_format);
+ }
+
static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
static const char* RUNTIME_ARG = "--runtime-arg";
@@ -756,6 +764,7 @@
+ (have_dex2oat_relocation_skip_flag ? 2 : 0)
+ (generate_debug_info ? 1 : 0)
+ (debuggable ? 1 : 0)
+ + (have_app_image_format ? 1 : 0)
+ dex2oat_flags_count
+ profile_files_fd.size()
+ reference_profile_files_fd.size()];
@@ -798,6 +807,9 @@
if (debuggable) {
argv[i++] = "--debuggable";
}
+ if (have_app_image_format) {
+ argv[i++] = image_format_arg;
+ }
if (dex2oat_flags_count) {
i += split(dex2oat_flags, argv + i);
}
@@ -983,13 +995,21 @@
}
}
-static int open_with_extension(char* file_name, const char* extension) {
- if (strlen(file_name) + strlen(extension) + 1 <= PKG_PATH_MAX) {
- strcat(file_name, extension);
- unlink(file_name);
- return open(file_name, O_RDWR | O_CREAT | O_EXCL, 0600);
+static bool add_extension_to_file_name(char* file_name, const char* extension) {
+ if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) {
+ return false;
}
- return -1;
+ strcat(file_name, extension);
+ return true;
+}
+
+static int open_output_file(char* file_name, bool recreate) {
+ int flags = O_RDWR | O_CREAT;
+ if (recreate) {
+ unlink(file_name);
+ flags |= O_EXCL;
+ }
+ return open(file_name, flags, 0600);
}
static bool set_permissions_and_ownership(int fd, bool is_public, int uid, const char* path) {
@@ -1103,7 +1123,9 @@
if (ShouldUseSwapFileForDexopt()) {
// Make sure there really is enough space.
strcpy(swap_file_name, out_path);
- swap_fd = open_with_extension(swap_file_name, ".swap");
+ if (add_extension_to_file_name(swap_file_name, ".swap")) {
+ swap_fd = open_output_file(swap_file_name, /*recreate*/true);
+ }
if (swap_fd < 0) {
// Could not create swap file. Optimistically go on and hope that we can compile
// without it.
@@ -1114,16 +1136,30 @@
}
}
+ // Avoid generating an app image for extract only since it will not contain any classes.
strcpy(image_path, out_path);
trim_extension(image_path);
- image_fd = open_with_extension(image_path, ".art");
- if (image_fd < 0) {
- // Could not create swap file. Optimistically go on and hope that we can compile
- // without it.
- ALOGE("installd could not create '%s' for image file during dexopt\n", image_path);
- } else if (!set_permissions_and_ownership(image_fd, is_public, uid, image_path)) {
- image_fd = -1;
+ if (add_extension_to_file_name(image_path, ".art")) {
+ char app_image_format[kPropertyValueMax];
+ bool have_app_image_format =
+ get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+ if (!extract_only && have_app_image_format) {
+ // Recreate is false since we want to avoid deleting the image in case dex2oat decides to
+ // not compile anything.
+ image_fd = open_output_file(image_path, /*recreate*/false);
+ if (image_fd < 0) {
+ // Could not create application image file. Go on since we can compile without it.
+ ALOGE("installd could not create '%s' for image file during dexopt\n", image_path);
+ } else if (!set_permissions_and_ownership(image_fd, is_public, uid, image_path)) {
+ image_fd = -1;
+ }
+ }
+ // If we have a valid image file path but no image fd, erase the image file.
+ if (image_fd < 0) {
+ unlink(image_path);
+ }
}
+
ALOGV("DexInv: --- BEGIN '%s' ---\n", input_file);
pid_t pid;
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 23cd066..e2e73a0 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -126,9 +126,11 @@
// waitWhileAllocatingLocked blocks until mIsAllocating is false.
void waitWhileAllocatingLocked() const;
+#if DEBUG_ONLY_CODE
// validateConsistencyLocked ensures that the free lists are in sync with
// the information stored in mSlots
void validateConsistencyLocked() const;
+#endif
// mAllocator is the connection to SurfaceFlinger that is used to allocate
// new GraphicBuffer objects.
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index ebce7fb..e983c16 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -206,17 +206,26 @@
virtual status_t setMaxBufferCount(int bufferCount) = 0;
// setMaxAcquiredBufferCount sets the maximum number of buffers that can
- // be acquired by the consumer at one time (default 1). This call will
- // fail if a producer is connected to the BufferQueue.
+ // be acquired by the consumer at one time (default 1). If this method
+ // succeeds, any new buffer slots will be both unallocated and owned by the
+ // BufferQueue object (i.e. they are not owned by the producer or consumer).
+ // Calling this may also cause some buffer slots to be emptied.
+ //
+ // This function should not be called with a value of maxAcquiredBuffers
+ // that is less than the number of currently acquired buffer slots. Doing so
+ // will result in a BAD_VALUE error.
//
// maxAcquiredBuffers must be (inclusive) between 1 and
// MAX_MAX_ACQUIRED_BUFFERS. It also cannot cause the maxBufferCount value
// to be exceeded.
//
// Return of a value other than NO_ERROR means an error has occurred:
+ // * NO_INIT - the buffer queue has been abandoned
// * BAD_VALUE - one of the below conditions occurred:
// * maxAcquiredBuffers was out of range (see above).
// * failure to adjust the number of available slots.
+ // * client would have more than the requested number of
+ // acquired buffers after this call
// * INVALID_OPERATION - attempting to call this after a producer connected.
virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0;
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 1f4c8ac..265728f 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -82,15 +82,16 @@
virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0;
// setMaxDequeuedBufferCount sets the maximum number of buffers that can be
- // dequeued by the producer at one time. If this method succeeds, buffer
- // slots will be both unallocated and owned by the BufferQueue object (i.e.
- // they are not owned by the producer or consumer). Calling this will also
- // cause all buffer slots to be emptied. If the caller is caching the
+ // dequeued by the producer at one time. If this method succeeds, any new
+ // buffer slots will be both unallocated and owned by the BufferQueue object
+ // (i.e. they are not owned by the producer or consumer). Calling this may
+ // also cause some buffer slots to be emptied. If the caller is caching the
// contents of the buffer slots, it should empty that cache after calling
// this method.
//
- // This function should not be called when there are any currently dequeued
- // buffer slots. Doing so will result in a BAD_VALUE error.
+ // This function should not be called with a value of maxDequeuedBuffers
+ // that is less than the number of currently dequeued buffer slots. Doing so
+ // will result in a BAD_VALUE error.
//
// The buffer count should be at least 1 (inclusive), but at most
// (NUM_BUFFER_SLOTS - the minimum undequeued buffer count) (exclusive). The
@@ -100,9 +101,10 @@
// Return of a value other than NO_ERROR means an error has occurred:
// * NO_INIT - the buffer queue has been abandoned.
// * BAD_VALUE - one of the below conditions occurred:
- // * bufferCount was out of range (see above)
- // * client has too many buffers dequeued
- // * this call would cause the maxBufferCount value to be exceeded
+ // * bufferCount was out of range (see above).
+ // * client would have more than the requested number of dequeued
+ // buffers after this call.
+ // * this call would cause the maxBufferCount value to be exceeded.
// * failure to adjust the number of available slots.
virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) = 0;
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 8a965dd..635020e 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -36,6 +36,8 @@
# Don't warn about struct padding
LOCAL_CPPFLAGS += -Wno-padded
+LOCAL_CPPFLAGS += -DDEBUG_ONLY_CODE=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
+
LOCAL_SRC_FILES := \
IGraphicBufferConsumer.cpp \
IConsumerListener.cpp \
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index d182f6b..92285e5 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -20,6 +20,12 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
+#if DEBUG_ONLY_CODE
+#define VALIDATE_CONSISTENCY() do { mCore->validateConsistencyLocked(); } while (0)
+#else
+#define VALIDATE_CONSISTENCY()
+#endif
+
#include <gui/BufferItem.h>
#include <gui/BufferQueueConsumer.h>
#include <gui/BufferQueueCore.h>
@@ -252,7 +258,7 @@
ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
}
if (listener != NULL) {
@@ -296,7 +302,7 @@
mCore->mFreeSlots.insert(slot);
mCore->clearBufferSlotLocked(slot);
mCore->mDequeueCondition.broadcast();
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
return NO_ERROR;
}
@@ -386,7 +392,7 @@
// for attached buffers.
mSlots[*outSlot].mAcquireCalled = false;
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
return NO_ERROR;
}
@@ -446,7 +452,7 @@
BQ_LOGV("releaseBuffer: releasing slot %d", slot);
mCore->mDequeueCondition.broadcast();
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
} // Autolock scope
// Call back without lock held
@@ -605,35 +611,59 @@
return BAD_VALUE;
}
- Mutex::Autolock lock(mCore->mMutex);
+ sp<IConsumerListener> listener;
+ { // Autolock scope
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked();
- if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
- BQ_LOGE("setMaxAcquiredBufferCount: producer is already connected");
- return INVALID_OPERATION;
+ if (mCore->mIsAbandoned) {
+ BQ_LOGE("setMaxAcquiredBufferCount: consumer is abandoned");
+ return NO_INIT;
+ }
+
+ // The new maxAcquiredBuffers count should not be violated by the number
+ // of currently acquired buffers
+ int acquiredCount = 0;
+ for (int slot : mCore->mActiveBuffers) {
+ if (mSlots[slot].mBufferState.isAcquired()) {
+ acquiredCount++;
+ }
+ }
+ if (acquiredCount > maxAcquiredBuffers) {
+ BQ_LOGE("setMaxAcquiredBufferCount: the requested maxAcquiredBuffer"
+ "count (%d) exceeds the current acquired buffer count (%d)",
+ maxAcquiredBuffers, acquiredCount);
+ return BAD_VALUE;
+ }
+
+ if ((maxAcquiredBuffers + mCore->mMaxDequeuedBufferCount +
+ (mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock ? 1 : 0))
+ > mCore->mMaxBufferCount) {
+ BQ_LOGE("setMaxAcquiredBufferCount: %d acquired buffers would "
+ "exceed the maxBufferCount (%d) (maxDequeued %d async %d)",
+ maxAcquiredBuffers, mCore->mMaxBufferCount,
+ mCore->mMaxDequeuedBufferCount, mCore->mAsyncMode ||
+ mCore->mDequeueBufferCannotBlock);
+ return BAD_VALUE;
+ }
+
+ int delta = maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount;
+ if (!mCore->adjustAvailableSlotsLocked(delta)) {
+ return BAD_VALUE;
+ }
+
+ BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
+ mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
+ VALIDATE_CONSISTENCY();
+ if (delta < 0) {
+ listener = mCore->mConsumerListener;
+ }
+ }
+ // Call back without lock held
+ if (listener != NULL) {
+ listener->onBuffersReleased();
}
- if ((maxAcquiredBuffers + mCore->mMaxDequeuedBufferCount +
- (mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock ? 1 : 0)) >
- mCore->mMaxBufferCount) {
- BQ_LOGE("setMaxAcquiredBufferCount: %d acquired buffers would exceed "
- "the maxBufferCount (%d) (maxDequeued %d async %d)",
- maxAcquiredBuffers, mCore->mMaxBufferCount,
- mCore->mMaxDequeuedBufferCount, mCore->mAsyncMode ||
- mCore->mDequeueBufferCannotBlock);
- return BAD_VALUE;
- }
-
- if (!mCore->adjustAvailableSlotsLocked(
- maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount)) {
- BQ_LOGE("setMaxAcquiredBufferCount: BufferQueue failed to adjust the "
- "number of available slots. Delta = %d",
- maxAcquiredBuffers - mCore->mMaxAcquiredBufferCount);
- return BAD_VALUE;
- }
-
- BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
- mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
- mCore->validateConsistencyLocked();
return NO_ERROR;
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index f02ff5f..f785db0 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -20,6 +20,12 @@
#define EGL_EGLEXT_PROTOTYPES
+#if DEBUG_ONLY_CODE
+#define VALIDATE_CONSISTENCY() do { validateConsistencyLocked(); } while (0)
+#else
+#define VALIDATE_CONSISTENCY()
+#endif
+
#include <inttypes.h>
#include <gui/BufferItem.h>
@@ -216,11 +222,15 @@
b.mIsStale = true;
}
- validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
}
bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
if (delta >= 0) {
+ // If we're going to fail, do so before modifying anything
+ if (delta > static_cast<int>(mUnusedSlots.size())) {
+ return false;
+ }
while (delta > 0) {
if (mUnusedSlots.empty()) {
return false;
@@ -231,6 +241,11 @@
delta--;
}
} else {
+ // If we're going to fail, do so before modifying anything
+ if (-delta > static_cast<int>(mFreeSlots.size() +
+ mFreeBuffers.size())) {
+ return false;
+ }
while (delta < 0) {
if (!mFreeSlots.empty()) {
auto slot = mFreeSlots.begin();
@@ -258,6 +273,7 @@
}
}
+#if DEBUG_ONLY_CODE
void BufferQueueCore::validateConsistencyLocked() const {
static const useconds_t PAUSE_TIME = 0;
int allocatedSlots = 0;
@@ -382,5 +398,6 @@
mUnusedSlots.size());
}
}
+#endif
} // namespace android
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 22a2d79..9d42464 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -20,6 +20,12 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
+#if DEBUG_ONLY_CODE
+#define VALIDATE_CONSISTENCY() do { mCore->validateConsistencyLocked(); } while (0)
+#else
+#define VALIDATE_CONSISTENCY()
+#endif
+
#define EGL_EGLEXT_PROTOTYPES
#include <gui/BufferItem.h>
@@ -95,13 +101,20 @@
return NO_INIT;
}
- // There must be no dequeued buffers when changing the buffer count.
+ // The new maxDequeuedBuffer count should not be violated by the number
+ // of currently dequeued buffers
+ int dequeuedCount = 0;
for (int s : mCore->mActiveBuffers) {
if (mSlots[s].mBufferState.isDequeued()) {
- BQ_LOGE("setMaxDequeuedBufferCount: buffer owned by producer");
- return BAD_VALUE;
+ dequeuedCount++;
}
}
+ if (dequeuedCount > maxDequeuedBuffers) {
+ BQ_LOGE("setMaxDequeuedBufferCount: the requested maxDequeuedBuffer"
+ "count (%d) exceeds the current dequeued buffer count (%d)",
+ maxDequeuedBuffers, dequeuedCount);
+ return BAD_VALUE;
+ }
int bufferCount = mCore->getMinUndequeuedBufferCountLocked();
bufferCount += maxDequeuedBuffers;
@@ -128,21 +141,16 @@
return BAD_VALUE;
}
- // Here we are guaranteed that the producer doesn't have any dequeued
- // buffers and will release all of its buffer references. We don't
- // clear the queue, however, so that currently queued buffers still
- // get displayed.
- if (!mCore->adjustAvailableSlotsLocked(
- maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount)) {
- BQ_LOGE("setMaxDequeuedBufferCount: BufferQueue failed to adjust "
- "the number of available slots. Delta = %d",
- maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount);
+ int delta = maxDequeuedBuffers - mCore->mMaxDequeuedBufferCount;
+ if (!mCore->adjustAvailableSlotsLocked(delta)) {
return BAD_VALUE;
}
mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers;
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
+ if (delta < 0) {
+ listener = mCore->mConsumerListener;
+ }
mCore->mDequeueCondition.broadcast();
- listener = mCore->mConsumerListener;
} // Autolock scope
// Call back without lock held
@@ -189,7 +197,7 @@
return BAD_VALUE;
}
mCore->mAsyncMode = async;
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
mCore->mDequeueCondition.broadcast();
listener = mCore->mConsumerListener;
} // Autolock scope
@@ -495,7 +503,7 @@
return NO_INIT;
}
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
} // Autolock scope
}
@@ -566,7 +574,7 @@
mCore->mFreeSlots.insert(slot);
mCore->clearBufferSlotLocked(slot);
mCore->mDequeueCondition.broadcast();
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
return NO_ERROR;
}
@@ -616,7 +624,7 @@
*outBuffer = mSlots[found].mGraphicBuffer;
*outFence = mSlots[found].mFence;
mCore->clearBufferSlotLocked(found);
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
return NO_ERROR;
}
@@ -684,7 +692,7 @@
mSlots[*outSlot].mRequestBufferCalled = true;
mSlots[*outSlot].mAcquireCalled = false;
mCore->mActiveBuffers.insert(found);
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
return returnFlags;
}
@@ -861,7 +869,7 @@
// Take a ticket for the callback functions
callbackTicket = mNextCallbackTicket++;
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
} // Autolock scope
// Don't send the GraphicBuffer through the callback, and don't send
@@ -948,7 +956,7 @@
mSlots[slot].mFence = fence;
mCore->mDequeueCondition.broadcast();
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
return NO_ERROR;
}
@@ -1087,7 +1095,7 @@
}
mCore->mAllowAllocation = true;
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
return status;
}
@@ -1252,7 +1260,7 @@
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.broadcast();
- mCore->validateConsistencyLocked();
+ VALIDATE_CONSISTENCY();
} // Autolock scope
}
}
@@ -1316,7 +1324,8 @@
mDequeueTimeout = timeout;
mCore->mDequeueBufferCannotBlock = false;
- mCore->validateConsistencyLocked();
+
+ VALIDATE_CONSISTENCY();
return NO_ERROR;
}
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index ac9af07..f4c47ed 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -179,6 +179,14 @@
sp<DummyConsumer> dc(new DummyConsumer);
mConsumer->consumerConnect(dc, false);
+ EXPECT_EQ(OK, mConsumer->setMaxBufferCount(10));
+ EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(10));
+
+ IGraphicBufferProducer::QueueBufferOutput qbo;
+ mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
+ &qbo);
+ mProducer->setMaxDequeuedBufferCount(3);
+
int minBufferCount;
ASSERT_NO_FATAL_FAILURE(GetMinUndequeuedBufferCount(&minBufferCount));
EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(
@@ -190,8 +198,24 @@
BufferQueue::MAX_MAX_ACQUIRED_BUFFERS+1));
EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(100));
- EXPECT_EQ(OK, mConsumer->setMaxBufferCount(5));
- EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(5));
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ IGraphicBufferProducer::QueueBufferInput qbi(0, false,
+ HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+ BufferItem item;
+ EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(3));
+ for (int i = 0; i < 3; i++) {
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+ mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
+ GRALLOC_USAGE_SW_READ_OFTEN));
+ ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
+ ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
+ ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+ }
+
+ EXPECT_EQ(BAD_VALUE, mConsumer->setMaxAcquiredBufferCount(2));
}
TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) {
@@ -199,12 +223,44 @@
sp<DummyConsumer> dc(new DummyConsumer);
mConsumer->consumerConnect(dc, false);
+ IGraphicBufferProducer::QueueBufferOutput qbo;
+ mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
+ &qbo);
+ mProducer->setMaxDequeuedBufferCount(2);
+
int minBufferCount;
ASSERT_NO_FATAL_FAILURE(GetMinUndequeuedBufferCount(&minBufferCount));
EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(2));
EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(minBufferCount));
+
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ IGraphicBufferProducer::QueueBufferInput qbi(0, false,
+ HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+ BufferItem item;
+
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+ mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
+ GRALLOC_USAGE_SW_READ_OFTEN));
+ ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
+ ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
+ ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+
+ EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(3));
+
+ for (int i = 0; i < 2; i++) {
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+ mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0,
+ GRALLOC_USAGE_SW_READ_OFTEN));
+ ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf));
+ ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo));
+ ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+ }
+
EXPECT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(
BufferQueue::MAX_MAX_ACQUIRED_BUFFERS));
}
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 882b14c..45b6463 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -502,31 +502,30 @@
ASSERT_OK(mProducer->setMaxDequeuedBufferCount(minBuffers))
<< "bufferCount: " << minBuffers;
- std::vector<DequeueBufferResult> dequeueList;
-
// Should now be able to dequeue up to minBuffers times
+ DequeueBufferResult result;
for (int i = 0; i < minBuffers; ++i) {
- DequeueBufferResult result;
EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
(dequeueBuffer(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
TEST_PRODUCER_USAGE_BITS, &result)))
<< "iteration: " << i << ", slot: " << result.slot;
-
- dequeueList.push_back(result);
- }
-
- // Cancel every buffer, so we can set buffer count again
- for (auto& result : dequeueList) {
- mProducer->cancelBuffer(result.slot, result.fence);
}
ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers));
+ // queue the first buffer to enable max dequeued buffer count checking
+ IGraphicBufferProducer::QueueBufferInput input = CreateBufferInput();
+ IGraphicBufferProducer::QueueBufferOutput output;
+ sp<GraphicBuffer> buffer;
+ ASSERT_OK(mProducer->requestBuffer(result.slot, &buffer));
+ ASSERT_OK(mProducer->queueBuffer(result.slot, input, &output));
+
+
// Should now be able to dequeue up to maxBuffers times
+ int dequeuedSlot = -1;
+ sp<Fence> dequeuedFence;
for (int i = 0; i < maxBuffers; ++i) {
- int dequeuedSlot = -1;
- sp<Fence> dequeuedFence;
EXPECT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
(mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
@@ -535,6 +534,12 @@
TEST_PRODUCER_USAGE_BITS)))
<< "iteration: " << i << ", slot: " << dequeuedSlot;
}
+
+ // Cancel a buffer, so we can decrease the buffer count
+ ASSERT_OK(mProducer->cancelBuffer(dequeuedSlot, dequeuedFence));
+
+ // Should now be able to decrease the max dequeued count by 1
+ ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers-1));
}
TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) {
@@ -553,11 +558,12 @@
EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(maxBuffers + 1))
<< "bufferCount: " << maxBuffers + 1;
- // Prerequisite to fail out a valid setBufferCount call
- {
- int dequeuedSlot = -1;
- sp<Fence> dequeuedFence;
-
+ // Set max dequeue count to 2
+ ASSERT_OK(mProducer->setMaxDequeuedBufferCount(2));
+ // Dequeue 2 buffers
+ int dequeuedSlot = -1;
+ sp<Fence> dequeuedFence;
+ for (int i = 0; i < 2; i++) {
ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
(mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
DEFAULT_WIDTH, DEFAULT_HEIGHT,
@@ -566,8 +572,8 @@
<< "slot: " << dequeuedSlot;
}
- // Client has one or more buffers dequeued
- EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(minBuffers))
+ // Client has too many buffers dequeued
+ EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(1))
<< "bufferCount: " << minBuffers;
// Abandon buffer queue
diff --git a/vulkan/libvulkan/loader.cpp b/vulkan/libvulkan/loader.cpp
index bc1c3b8..939f3b9 100644
--- a/vulkan/libvulkan/loader.cpp
+++ b/vulkan/libvulkan/loader.cpp
@@ -600,13 +600,6 @@
return result;
}
- if (!LoadDriverDispatchTable(instance.drv.instance,
- g_hwdevice->GetInstanceProcAddr,
- enabled_extensions, instance.drv.dispatch)) {
- DestroyInstance_Bottom(instance.handle, allocator);
- return VK_ERROR_INITIALIZATION_FAILED;
- }
-
hwvulkan_dispatch_t* drv_dispatch =
reinterpret_cast<hwvulkan_dispatch_t*>(instance.drv.instance);
if (drv_dispatch->magic == HWVULKAN_DISPATCH_MAGIC) {
@@ -619,6 +612,13 @@
return VK_ERROR_INITIALIZATION_FAILED;
}
+ if (!LoadDriverDispatchTable(instance.drv.instance,
+ g_hwdevice->GetInstanceProcAddr,
+ enabled_extensions, instance.drv.dispatch)) {
+ DestroyInstance_Bottom(instance.handle, allocator);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
uint32_t num_physical_devices = 0;
result = instance.drv.dispatch.EnumeratePhysicalDevices(
instance.drv.instance, &num_physical_devices, nullptr);
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 2392b5c..bab5a59 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -346,10 +346,8 @@
"swapchain re-creation not yet implemented");
ALOGE_IF(create_info->preTransform != VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
"swapchain preTransform not yet implemented");
- ALOGW_IF((create_info->presentMode != VK_PRESENT_MODE_FIFO_KHR ||
- create_info->presentMode != VK_PRESENT_MODE_MAILBOX_KHR),
- "swapchain present mode %d not supported",
- create_info->presentMode);
+ ALOGE_IF(create_info->presentMode != VK_PRESENT_MODE_FIFO_KHR,
+ "present modes other than FIFO are not yet implemented");
// -- Configure the native window --
@@ -420,17 +418,6 @@
return VK_ERROR_INITIALIZATION_FAILED;
}
- err = surface.window->setSwapInterval(
- surface.window.get(),
- create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1);
- if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
- ALOGE("native_window->setSwapInterval failed: %s (%d)", strerror(-err),
- err);
- return VK_ERROR_INITIALIZATION_FAILED;
- }
-
// -- Allocate our Swapchain object --
// After this point, we must deallocate the swapchain on error.