diff options
119 files changed, 2036 insertions, 4081 deletions
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 1911839..6d6f77e 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -82,6 +82,7 @@ static const TracingCategory k_categories[] = { { "hal", "Hardware Modules", ATRACE_TAG_HAL, { } }, { "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } }, { "dalvik", "Dalvik VM", ATRACE_TAG_DALVIK, { } }, + { "rs", "RenderScript", ATRACE_TAG_RS, { } }, { "sched", "CPU Scheduling", 0, { { REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" }, { REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" }, diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp index c9fcc00..ce8993d 100644 --- a/cmds/dumpsys/dumpsys.cpp +++ b/cmds/dumpsys/dumpsys.cpp @@ -9,7 +9,7 @@ #include <binder/Parcel.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> -#include <utils/TextOutput.h> +#include <binder/TextOutput.h> #include <utils/Vector.h> #include <getopt.h> @@ -39,7 +39,11 @@ int main(int argc, char* const argv[]) Vector<String16> services; Vector<String16> args; - if (argc == 1) { + bool showListOnly = false; + if ((argc == 2) && (strcmp(argv[1], "-l") == 0)) { + showListOnly = true; + } + if ((argc == 1) || showListOnly) { services = sm->listServices(); services.sort(sort_func); args.add(String16("-a")); @@ -64,6 +68,10 @@ int main(int argc, char* const argv[]) } } + if (showListOnly) { + return 0; + } + for (size_t i=0; i<N; i++) { sp<IBinder> service = sm->checkService(services[i]); if (service != NULL) { diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp index 99715d3..d6ac3d2 100644 --- a/cmds/flatland/Main.cpp +++ b/cmds/flatland/Main.cpp @@ -56,7 +56,7 @@ struct BenchmarkDesc { static const BenchmarkDesc benchmarks[] = { { "16:10 Single Static Window", - 2560, 1600, { 800, 1600, 2400 }, + 2560, 1600, { 800, 1200, 1600, 2400 }, { { // Window 0, staticGradient, opaque, @@ -73,8 +73,26 @@ static const BenchmarkDesc benchmarks[] = { }, }, + { "3:2 Single Static Window", + 2048, 1536, { 1536 }, + { + { // Window + 0, staticGradient, opaque, + 0, 50, 2048, 1440, + }, + { // Status bar + 0, staticGradient, opaque, + 0, 0, 2048, 50, + }, + { // Navigation bar + 0, staticGradient, opaque, + 0, 1440, 2048, 96, + }, + }, + }, + { "16:10 App -> Home Transition", - 2560, 1600, { 800, 1600, 2400 }, + 2560, 1600, { 800, 1200, 1600, 2400 }, { { // Wallpaper 0, staticGradient, opaque, @@ -99,8 +117,34 @@ static const BenchmarkDesc benchmarks[] = { }, }, + { "3:2 App -> Home Transition", + 2048, 1536, { 1536 }, + { + { // Wallpaper + 0, staticGradient, opaque, + 0, 50, 2048, 1440, + }, + { // Launcher + 0, staticGradient, blend, + 0, 50, 2048, 1440, + }, + { // Outgoing activity + 0, staticGradient, blendShrink, + 20, 70, 2048, 1400, + }, + { // Status bar + 0, staticGradient, opaque, + 0, 0, 2048, 50, + }, + { // Navigation bar + 0, staticGradient, opaque, + 0, 1440, 2048, 96, + }, + }, + }, + { "16:10 SurfaceView -> Home Transition", - 2560, 1600, { 800, 1600, 2400 }, + 2560, 1600, { 800, 1200, 1600, 2400 }, { { // Wallpaper 0, staticGradient, opaque, @@ -128,6 +172,36 @@ static const BenchmarkDesc benchmarks[] = { }, }, }, + + { "3:2 SurfaceView -> Home Transition", + 2048, 1536, { 1536 }, + { + { // Wallpaper + 0, staticGradient, opaque, + 0, 50, 2048, 1440, + }, + { // Launcher + 0, staticGradient, blend, + 0, 50, 2048, 1440, + }, + { // Outgoing SurfaceView + 0, staticGradient, blendShrink, + 20, 70, 2048, 1400, + }, + { // Outgoing activity + 0, staticGradient, blendShrink, + 20, 70, 2048, 1400, + }, + { // Status bar + 0, staticGradient, opaque, + 0, 0, 2048, 50, + }, + { // Navigation bar + 0, staticGradient, opaque, + 0, 1440, 2048, 96, + }, + }, + }, }; static const ShaderDesc shaders[] = { diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index 8e14a2c..131e03f 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -540,7 +540,6 @@ done: } -/* a simpler version of dexOptGenerateCacheFileName() */ int create_cache_path(char path[PKG_PATH_MAX], const char *src) { char *tmp; @@ -580,7 +579,7 @@ int create_cache_path(char path[PKG_PATH_MAX], const char *src) } static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name, - const char* dexopt_flags) + const char* output_file_name, const char* dexopt_flags) { static const char* DEX_OPT_BIN = "/system/bin/dexopt"; static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig @@ -590,11 +589,35 @@ static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name, sprintf(zip_num, "%d", zip_fd); sprintf(odex_num, "%d", odex_fd); + ALOGV("Running %s in=%s out=%s\n", DEX_OPT_BIN, input_file_name, output_file_name); execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name, dexopt_flags, (char*) NULL); ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno)); } +static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, + const char* output_file_name, const char* dexopt_flags) +{ + static const char* DEX2OAT_BIN = "/system/bin/dex2oat"; + static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig + char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN]; + char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX]; + char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN]; + char oat_location_arg[strlen("--oat-name=") + PKG_PATH_MAX]; + + sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd); + sprintf(zip_location_arg, "--zip-location=%s", input_file_name); + sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd); + sprintf(oat_location_arg, "--oat-location=%s", output_file_name); + + ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name); + execl(DEX2OAT_BIN, DEX2OAT_BIN, + zip_fd_arg, zip_location_arg, + oat_fd_arg, oat_location_arg, + (char*) NULL); + ALOGE("execl(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno)); +} + static int wait_dexopt(pid_t pid, const char* apk_path) { int status; @@ -631,31 +654,33 @@ int dexopt(const char *apk_path, uid_t uid, int is_public) { struct utimbuf ut; struct stat apk_stat, dex_stat; - char dex_path[PKG_PATH_MAX]; + char out_path[PKG_PATH_MAX]; char dexopt_flags[PROPERTY_VALUE_MAX]; + char dalvik_vm_lib[PROPERTY_VALUE_MAX]; char *end; - int res, zip_fd=-1, odex_fd=-1; + int res, zip_fd=-1, out_fd=-1; - /* Before anything else: is there a .odex file? If so, we have - * pre-optimized the apk and there is nothing to do here. - */ if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { return -1; } /* platform-specific flags affecting optimization and verification */ property_get("dalvik.vm.dexopt-flags", dexopt_flags, ""); + ALOGV("dalvik.vm.dexopt_flags=%s\n", dexopt_flags); - strcpy(dex_path, apk_path); - end = strrchr(dex_path, '.'); - if (end != NULL) { - strcpy(end, ".odex"); - if (stat(dex_path, &dex_stat) == 0) { - return 0; - } + /* The command to run depend ones the value of dalvik.vm.lib */ + property_get("dalvik.vm.lib", dalvik_vm_lib, "libdvm.so"); + ALOGV("dalvik.vm.lib=%s\n", dalvik_vm_lib); + + /* Before anything else: is there a .odex file? If so, we have + * precompiled the apk and there is nothing to do here. + */ + sprintf(out_path, "%s%s", apk_path, ".odex"); + if (stat(out_path, &dex_stat) == 0) { + return 0; } - if (create_cache_path(dex_path, apk_path)) { + if (create_cache_path(out_path, apk_path)) { return -1; } @@ -664,24 +689,24 @@ int dexopt(const char *apk_path, uid_t uid, int is_public) zip_fd = open(apk_path, O_RDONLY, 0); if (zip_fd < 0) { - ALOGE("dexopt cannot open '%s' for input\n", apk_path); + ALOGE("installd cannot open '%s' for input during dexopt\n", apk_path); return -1; } - unlink(dex_path); - odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644); - if (odex_fd < 0) { - ALOGE("dexopt cannot open '%s' for output\n", dex_path); + unlink(out_path); + out_fd = open(out_path, O_RDWR | O_CREAT | O_EXCL, 0644); + if (out_fd < 0) { + ALOGE("installd cannot open '%s' for output during dexopt\n", out_path); goto fail; } - if (fchmod(odex_fd, + if (fchmod(out_fd, S_IRUSR|S_IWUSR|S_IRGRP | (is_public ? S_IROTH : 0)) < 0) { - ALOGE("dexopt cannot chmod '%s'\n", dex_path); + ALOGE("installd cannot chmod '%s' during dexopt\n", out_path); goto fail; } - if (fchown(odex_fd, AID_SYSTEM, uid) < 0) { - ALOGE("dexopt cannot chown '%s'\n", dex_path); + if (fchown(out_fd, AID_SYSTEM, uid) < 0) { + ALOGE("installd cannot chown '%s' during dexopt\n", out_path); goto fail; } @@ -692,11 +717,11 @@ int dexopt(const char *apk_path, uid_t uid, int is_public) if (pid == 0) { /* child -- drop privileges before continuing */ if (setgid(uid) != 0) { - ALOGE("setgid(%d) failed during dexopt\n", uid); + ALOGE("setgid(%d) failed in installd during dexopt\n", uid); exit(64); } if (setuid(uid) != 0) { - ALOGE("setuid(%d) during dexopt\n", uid); + ALOGE("setuid(%d) failed in installd during dexopt\n", uid); exit(65); } // drop capabilities @@ -709,33 +734,39 @@ int dexopt(const char *apk_path, uid_t uid, int is_public) ALOGE("capset failed: %s\n", strerror(errno)); exit(66); } - if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) { - ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno)); + if (flock(out_fd, LOCK_EX | LOCK_NB) != 0) { + ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno)); exit(67); } - run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags); + if (strncmp(dalvik_vm_lib, "libdvm", 6) == 0) { + run_dexopt(zip_fd, out_fd, apk_path, out_path, dexopt_flags); + } else if (strncmp(dalvik_vm_lib, "libart", 6) == 0) { + run_dex2oat(zip_fd, out_fd, apk_path, out_path, dexopt_flags); + } else { + exit(69); /* Unexpected dalvik.vm.lib value */ + } exit(68); /* only get here on exec failure */ } else { res = wait_dexopt(pid, apk_path); if (res != 0) { - ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res); + ALOGE("dexopt in='%s' out='%s' res=%d\n", apk_path, out_path, res); goto fail; } } ut.actime = apk_stat.st_atime; ut.modtime = apk_stat.st_mtime; - utime(dex_path, &ut); - - close(odex_fd); + utime(out_path, &ut); + + close(out_fd); close(zip_fd); return 0; fail: - if (odex_fd >= 0) { - close(odex_fd); - unlink(dex_path); + if (out_fd >= 0) { + close(out_fd); + unlink(out_path); } if (zip_fd >= 0) { close(zip_fd); diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c index c918633..87f900a 100644 --- a/cmds/installd/installd.c +++ b/cmds/installd/installd.c @@ -198,7 +198,7 @@ static int execute(int s, char cmd[BUFFER_MAX]) unsigned short count; int ret = -1; -// ALOGI("execute('%s')\n", cmd); + // ALOGI("execute('%s')\n", cmd); /* default reply is "" */ reply[0] = 0; @@ -240,7 +240,7 @@ done: if (n > BUFFER_MAX) n = BUFFER_MAX; count = n; -// ALOGI("reply: '%s'\n", cmd); + // ALOGI("reply: '%s'\n", cmd); if (writex(s, &count, sizeof(count))) return -1; if (writex(s, cmd, count)) return -1; return 0; diff --git a/cmds/rawbu/backup.cpp b/cmds/rawbu/backup.cpp index 70e7b57..ff6719f 100644 --- a/cmds/rawbu/backup.cpp +++ b/cmds/rawbu/backup.cpp @@ -639,6 +639,12 @@ static void show_help(const char *cmd) fprintf(stderr, "options include:\n" " -h Show this help text.\n" " -a Backup all files.\n"); + fprintf(stderr, "\n backup-file-path Defaults to /sdcard/backup.dat .\n" + " On devices that emulate the sdcard, you will need to\n" + " explicitly specify the directory it is mapped to,\n" + " to avoid recursive backup or deletion of the backup file\n" + " during restore.\n\n" + " Eg. /data/media/0/backup.dat\n"); fprintf(stderr, "\nThe %s command allows you to perform low-level\n" "backup and restore of the /data partition. This is\n" "where all user data is kept, allowing for a fairly\n" diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp index 32db83b..97fc47c 100644 --- a/cmds/service/service.cpp +++ b/cmds/service/service.cpp @@ -1,12 +1,23 @@ /* - * Command line access to services. + * Copyright 2013 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 <binder/Parcel.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> -#include <utils/TextOutput.h> +#include <binder/TextOutput.h> #include <getopt.h> #include <stdlib.h> diff --git a/include/binder/BinderService.h b/include/binder/BinderService.h index 5ac36d9..ef703bd 100644 --- a/include/binder/BinderService.h +++ b/include/binder/BinderService.h @@ -42,19 +42,20 @@ public: } static void publishAndJoinThreadPool(bool allowIsolated = false) { - sp<IServiceManager> sm(defaultServiceManager()); - sm->addService( - String16(SERVICE::getServiceName()), - new SERVICE(), allowIsolated); - ProcessState::self()->startThreadPool(); - ProcessState::self()->giveThreadPoolName(); - IPCThreadState::self()->joinThreadPool(); + publish(allowIsolated); + joinThreadPool(); } static void instantiate() { publish(); } - static status_t shutdown() { - return NO_ERROR; + static status_t shutdown() { return NO_ERROR; } + +private: + static void joinThreadPool() { + sp<ProcessState> ps(ProcessState::self()); + ps->startThreadPool(); + ps->giveThreadPoolName(); + IPCThreadState::self()->joinThreadPool(); } }; diff --git a/include/utils/BufferedTextOutput.h b/include/binder/BufferedTextOutput.h index 69c6240..adf3c32 100644 --- a/include/utils/BufferedTextOutput.h +++ b/include/binder/BufferedTextOutput.h @@ -17,7 +17,7 @@ #ifndef ANDROID_BUFFEREDTEXTOUTPUT_H #define ANDROID_BUFFEREDTEXTOUTPUT_H -#include <utils/TextOutput.h> +#include <binder/TextOutput.h> #include <utils/threads.h> #include <cutils/uio.h> diff --git a/include/binder/Debug.h b/include/binder/Debug.h new file mode 100644 index 0000000..f6a3355 --- /dev/null +++ b/include/binder/Debug.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005 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. + */ + +#ifndef ANDROID_BINDER_DEBUG_H +#define ANDROID_BINDER_DEBUG_H + +#include <stdint.h> +#include <sys/types.h> + +namespace android { +// --------------------------------------------------------------------------- + +#ifdef __cplusplus +extern "C" { +#endif + +const char* stringForIndent(int32_t indentLevel); + +typedef void (*debugPrintFunc)(void* cookie, const char* txt); + +void printTypeCode(uint32_t typeCode, + debugPrintFunc func = 0, void* cookie = 0); + +void printHexData(int32_t indent, const void *buf, size_t length, + size_t bytesPerLine=16, int32_t singleLineBytesCutoff=16, + size_t alignment=0, bool cArrayStyle=false, + debugPrintFunc func = 0, void* cookie = 0); + +#ifdef __cplusplus +} +#endif + +// --------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_BINDER_DEBUG_H diff --git a/include/utils/TextOutput.h b/include/binder/TextOutput.h index de2fbbe..974a194 100644 --- a/include/utils/TextOutput.h +++ b/include/binder/TextOutput.h @@ -25,6 +25,9 @@ // --------------------------------------------------------------------------- namespace android { +class String8; +class String16; + class TextOutput { public: @@ -76,6 +79,8 @@ TextOutput& operator<<(TextOutput& to, float); TextOutput& operator<<(TextOutput& to, double); TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func); TextOutput& operator<<(TextOutput& to, const void*); +TextOutput& operator<<(TextOutput& to, const String8& val); +TextOutput& operator<<(TextOutput& to, const String16& val); class TypeCode { diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 6c1b691..766fa0f 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -229,7 +229,7 @@ public: // dump our state in a String virtual void dump(String8& result) const; - virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; + virtual void dump(String8& result, const char* prefix) const; // public facing structure for BufferSlot struct BufferItem { @@ -240,7 +240,8 @@ public: mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT) { + mBuf(INVALID_BUFFER_SLOT), + mAcquireCalled(false) { mCrop.makeInvalid(); } // mGraphicBuffer points to the buffer allocated for this slot, or is NULL @@ -269,6 +270,9 @@ public: // mFence is a fence that will signal when the buffer is idle. sp<Fence> mFence; + + // Indicates whether this buffer has been seen by a consumer yet + bool mAcquireCalled; }; // The following public functions are the consumer-facing interface @@ -285,7 +289,7 @@ public: // releaseBuffer releases a buffer slot from the consumer back to the // BufferQueue. This may be done while the buffer's contents are still // being accessed. The fence will signal when the buffer is no longer - // in use. + // in use. frameNumber is used to indentify the exact buffer returned. // // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free // any references to the just-released buffer that it might have, as if it @@ -294,7 +298,8 @@ public: // // Note that the dependencies on EGL will be removed once we switch to using // the Android HW Sync HAL. - status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence, + status_t releaseBuffer(int buf, uint64_t frameNumber, + EGLDisplay display, EGLSyncKHR fence, const sp<Fence>& releaseFence); // consumerConnect connects a consumer to the BufferQueue. Only one @@ -368,10 +373,6 @@ private: // all slots. void freeAllBuffersLocked(); - // freeAllBuffersExceptHeadLocked frees the GraphicBuffer and sync - // resources for all slots except the head of mQueue. - void freeAllBuffersExceptHeadLocked(); - // drainQueueLocked waits for the buffer queue to empty if we're in // synchronous mode, or returns immediately otherwise. It returns NO_INIT // if the BufferQueue is abandoned (consumer disconnected) or disconnected @@ -410,20 +411,20 @@ private: // connected, mDequeueCondition must be broadcast. int getMaxBufferCountLocked() const; + // stillTracking returns true iff the buffer item is still being tracked + // in one of the slots. + bool stillTracking(const BufferItem *item) const; + struct BufferSlot { BufferSlot() : mEglDisplay(EGL_NO_DISPLAY), mBufferState(BufferSlot::FREE), mRequestBufferCalled(false), - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), mFrameNumber(0), mEglFence(EGL_NO_SYNC_KHR), mAcquireCalled(false), mNeedsCleanupOnRelease(false) { - mCrop.makeInvalid(); } // mGraphicBuffer points to the buffer allocated for this slot or is NULL @@ -482,21 +483,6 @@ private: // needed but useful for debugging and catching producer bugs. bool mRequestBufferCalled; - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - // (example: NATIVE_WINDOW_TRANSFORM_ROT_90) - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - // (example: NATIVE_WINDOW_SCALING_MODE_FREEZE) - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - // mFrameNumber is the number of the queued frame for this slot. This // is used to dequeue buffers in LRU order (useful because buffers // may be released before their release fence is signaled). @@ -592,7 +578,7 @@ private: mutable Condition mDequeueCondition; // mQueue is a FIFO of queued buffers used in synchronous mode - typedef Vector<int> Fifo; + typedef Vector<BufferItem> Fifo; Fifo mQueue; // mAbandoned indicates that the BufferQueue will no longer be used to @@ -613,7 +599,7 @@ private: mutable Mutex mMutex; // mFrameCounter is the free running counter, incremented on every - // successful queueBuffer call. + // successful queueBuffer call, and buffer allocation. uint64_t mFrameCounter; // mBufferHasBeenQueued is true once a buffer has been queued. It is diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h index 8a7545d..1d51bc9 100644 --- a/include/gui/ConsumerBase.h +++ b/include/gui/ConsumerBase.h @@ -73,7 +73,7 @@ public: // their state to the dump by overriding the dumpLocked method, which is // called by these methods after locking the mutex. void dump(String8& result) const; - void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; + void dump(String8& result, const char* prefix) const; // setFrameAvailableListener sets the listener object that will be notified // when a new frame becomes available. @@ -143,8 +143,7 @@ protected: // should call ConsumerBase::dumpLocked. // // This method must be called with mMutex locked. - virtual void dumpLocked(String8& result, const char* prefix, char* buffer, - size_t size) const; + virtual void dumpLocked(String8& result, const char* prefix) const; // acquireBufferLocked fetches the next buffer from the BufferQueue and // updates the buffer slot for the buffer returned. @@ -161,17 +160,23 @@ protected: // Derived classes should override this method to perform any cleanup that // must take place when a buffer is released back to the BufferQueue. If // it is overridden the derived class's implementation must call - // ConsumerBase::releaseBufferLocked. - virtual status_t releaseBufferLocked(int buf, EGLDisplay display, - EGLSyncKHR eglFence); + // ConsumerBase::releaseBufferLocked.e + virtual status_t releaseBufferLocked(int slot, + const sp<GraphicBuffer> graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence); + + // returns true iff the slot still has the graphicBuffer in it. + bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer); // addReleaseFence* adds the sync points associated with a fence to the set // of sync points that must be reached before the buffer in the given slot // may be used after the slot has been released. This should be called by // derived classes each time some asynchronous work is kicked off that // references the buffer. - status_t addReleaseFence(int slot, const sp<Fence>& fence); - status_t addReleaseFenceLocked(int slot, const sp<Fence>& fence); + status_t addReleaseFence(int slot, + const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence); + status_t addReleaseFenceLocked(int slot, + const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence); // Slot contains the information and object references that // ConsumerBase maintains about a BufferQueue buffer slot. @@ -185,6 +190,9 @@ protected: // overwritten. The buffer can be dequeued before the fence signals; // the producer is responsible for delaying writes until it signals. sp<Fence> mFence; + + // the frame number of the last acquired frame for this slot + uint64_t mFrameNumber; }; // mSlots stores the buffers that have been allocated by the BufferQueue diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h index bf9918e..3c178ef 100644 --- a/include/gui/CpuConsumer.h +++ b/include/gui/CpuConsumer.h @@ -25,7 +25,6 @@ #include <utils/Vector.h> #include <utils/threads.h> -#define ANDROID_GRAPHICS_CPUCONSUMER_JNI_ID "mCpuConsumer" namespace android { @@ -73,6 +72,18 @@ class CpuConsumer : public ConsumerBase // log messages. void setName(const String8& name); + // setDefaultBufferSize is used to set the size of buffers returned by + // requestBuffers when a width and height of zero is requested. + // A call to setDefaultBufferSize() may trigger requestBuffers() to + // be called from the client. Default size is 1x1. + status_t setDefaultBufferSize(uint32_t width, uint32_t height); + + // setDefaultBufferFormat allows CpuConsumer's BufferQueue to create buffers + // of a defaultFormat if no format is specified by producer. Formats are + // enumerated in graphics.h; the initial default is + // HAL_PIXEL_FORMAT_RGBA_8888. + status_t setDefaultBufferFormat(uint32_t defaultFormat); + // Gets the next graphics buffer from the producer and locks it for CPU use, // filling out the passed-in locked buffer structure with the native pointer // and metadata. Returns BAD_VALUE if no new buffer is available, and diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h index f0a75dc..031684e 100644 --- a/include/gui/GLConsumer.h +++ b/include/gui/GLConsumer.h @@ -233,8 +233,7 @@ protected: // dumpLocked overrides the ConsumerBase method to dump GLConsumer- // specific info in addition to the ConsumerBase behavior. - virtual void dumpLocked(String8& result, const char* prefix, char* buffer, - size_t size) const; + virtual void dumpLocked(String8& result, const char* prefix) const; // acquireBufferLocked overrides the ConsumerBase method to update the // mEglSlots array in addition to the ConsumerBase behavior. @@ -242,11 +241,13 @@ protected: // releaseBufferLocked overrides the ConsumerBase method to update the // mEglSlots array in addition to the ConsumerBase. - virtual status_t releaseBufferLocked(int buf, EGLDisplay display, - EGLSyncKHR eglFence); + virtual status_t releaseBufferLocked(int slot, + const sp<GraphicBuffer> graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence); - status_t releaseBufferLocked(int buf, EGLSyncKHR eglFence) { - return releaseBufferLocked(buf, mEglDisplay, eglFence); + status_t releaseBufferLocked(int slot, + const sp<GraphicBuffer> graphicBuffer, EGLSyncKHR eglFence) { + return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence); } static bool isExternalFormat(uint32_t format); diff --git a/include/media/hardware/HDCPAPI.h b/include/media/hardware/HDCPAPI.h index 147448e..b3f4222 100644 --- a/include/media/hardware/HDCPAPI.h +++ b/include/media/hardware/HDCPAPI.h @@ -19,6 +19,7 @@ #define HDCP_API_H_ #include <utils/Errors.h> +#include <system/window.h> namespace android { @@ -90,6 +91,20 @@ struct HDCPModule { return INVALID_OPERATION; } + // Encrypt data according to the HDCP spec. "size" bytes of data starting + // at location "offset" are available in "buffer" (buffer handle). "size" + // may not be a multiple of 128 bits (16 bytes). An equal number of + // encrypted bytes should be written to the buffer at "outData" (virtual + // address). This operation is to be synchronous, i.e. this call does not + // return until outData contains size bytes of encrypted data. + // streamCTR will be assigned by the caller (to 0 for the first PES stream, + // 1 for the second and so on) + // inputCTR _will_be_maintained_by_the_callee_ for each PES stream. + virtual status_t encryptNative( + buffer_handle_t buffer, size_t offset, size_t size, + uint32_t streamCTR, uint64_t *outInputCTR, void *outData) { + return INVALID_OPERATION; + } // DECRYPTION only: // Decrypt data according to the HDCP spec. // "size" bytes of encrypted data are available at "inData" diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h index cc43bf6..a6a849d 100644 --- a/include/media/hardware/HardwareAPI.h +++ b/include/media/hardware/HardwareAPI.h @@ -18,7 +18,8 @@ #define HARDWARE_API_H_ -#include <OMXPluginBase.h> +#include <media/hardware/OMXPluginBase.h> +#include <media/hardware/MetadataBufferType.h> #include <system/window.h> #include <utils/RefBase.h> @@ -73,6 +74,13 @@ struct StoreMetaDataInBuffersParams { OMX_BOOL bStoreMetaData; }; +// Meta data buffer layout used to transport output frames to the decoder for +// dynamic buffer handling. +struct VideoDecoderOutputMetaData { + MetadataBufferType eType; + buffer_handle_t pHandle; +}; + // A pointer to this struct is passed to OMX_SetParameter when the extension // index for the 'OMX.google.android.index.useAndroidNativeBuffer' extension is // given. This call will only be performed if a prior call was made with the diff --git a/include/media/openmax/OMX_IVCommon.h b/include/media/openmax/OMX_IVCommon.h index 85bf00d..96a4396 100644 --- a/include/media/openmax/OMX_IVCommon.h +++ b/include/media/openmax/OMX_IVCommon.h @@ -161,6 +161,7 @@ typedef enum OMX_COLOR_FORMATTYPE { OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00, OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka = 0x7FA30C03, OMX_SEC_COLOR_FormatNV12Tiled = 0x7FC00002, + OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m = 0x7FA30C04, OMX_COLOR_FormatMax = 0x7FFFFFFF } OMX_COLOR_FORMATTYPE; diff --git a/include/media/openmax/OMX_Video.h b/include/media/openmax/OMX_Video.h index 4f8485d..4441a7a 100644 --- a/include/media/openmax/OMX_Video.h +++ b/include/media/openmax/OMX_Video.h @@ -85,7 +85,8 @@ typedef enum OMX_VIDEO_CODINGTYPE { OMX_VIDEO_CodingRV, /**< all versions of Real Video */ OMX_VIDEO_CodingAVC, /**< H.264/AVC */ OMX_VIDEO_CodingMJPEG, /**< Motion JPEG */ - OMX_VIDEO_CodingVPX, /**< Google VPX, formerly known as On2 VP8 */ + OMX_VIDEO_CodingVP8, /**< Google VP8, formerly known as On2 VP8 */ + OMX_VIDEO_CodingVP9, /**< Google VP9 */ OMX_VIDEO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ OMX_VIDEO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ OMX_VIDEO_CodingMax = 0x7FFFFFFF diff --git a/include/media/openmax/OMX_VideoExt.h b/include/media/openmax/OMX_VideoExt.h index 5e79b47..fa24168 100644 --- a/include/media/openmax/OMX_VideoExt.h +++ b/include/media/openmax/OMX_VideoExt.h @@ -58,12 +58,6 @@ typedef struct OMX_NALSTREAMFORMATTYPE{ OMX_NALUFORMATSTYPE eNaluFormat; } OMX_NALSTREAMFORMATTYPE; -/** Enum for standard video codingtype extensions */ -typedef enum OMX_VIDEO_CODINGEXTTYPE { - OMX_VIDEO_ExtCodingUnused = OMX_VIDEO_CodingKhronosExtensions, - OMX_VIDEO_CodingVP8, /**< VP8/WebM */ -} OMX_VIDEO_CODINGEXTTYPE; - /** VP8 profiles */ typedef enum OMX_VIDEO_VP8PROFILETYPE { OMX_VIDEO_VP8ProfileMain = 0x01, diff --git a/include/powermanager/IPowerManager.h b/include/powermanager/IPowerManager.h index 1723f04..e21e6a8 100644 --- a/include/powermanager/IPowerManager.h +++ b/include/powermanager/IPowerManager.h @@ -30,7 +30,8 @@ class IPowerManager : public IInterface public: DECLARE_META_INTERFACE(PowerManager); - virtual status_t acquireWakeLock(int flags, const sp<IBinder>& lock, const String16& tag) = 0; + virtual status_t acquireWakeLock(int flags, const sp<IBinder>& lock, const String16& tag, + const String16& packageName) = 0; virtual status_t releaseWakeLock(const sp<IBinder>& lock, int flags) = 0; }; diff --git a/include/private/binder/Static.h b/include/private/binder/Static.h index 5b0f9fc..6a03594 100644 --- a/include/private/binder/Static.h +++ b/include/private/binder/Static.h @@ -27,6 +27,9 @@ namespace android { +// For TextStream.cpp +extern Vector<int32_t> gTextBuffers; + // For ProcessState.cpp extern Mutex gProcessMutex; extern sp<ProcessState> gProcess; diff --git a/include/private/utils/Static.h b/include/private/utils/Static.h deleted file mode 100644 index d95ae0d..0000000 --- a/include/private/utils/Static.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -// All static variables go here, to control initialization and -// destruction order in the library. - -#include <utils/threads.h> -#include <utils/KeyedVector.h> - -namespace android { -// For TextStream.cpp -extern Vector<int32_t> gTextBuffers; - -// For String8.cpp -extern void initialize_string8(); -extern void terminate_string8(); - -// For String16.cpp -extern void initialize_string16(); -extern void terminate_string16(); - -} // namespace android diff --git a/include/ui/Rect.h b/include/ui/Rect.h index 47d37b6..6cf64eb 100644 --- a/include/ui/Rect.h +++ b/include/ui/Rect.h @@ -35,14 +35,25 @@ public: inline Rect() { } + inline Rect(int32_t w, int32_t h) { - left = top = 0; right = w; bottom = h; + left = top = 0; + right = w; + bottom = h; } + inline Rect(int32_t l, int32_t t, int32_t r, int32_t b) { - left = l; top = t; right = r; bottom = b; + left = l; + top = t; + right = r; + bottom = b; } + inline Rect(const Point& lt, const Point& rb) { - left = lt.x; top = lt.y; right = rb.x; bottom = rb.y; + left = lt.x; + top = lt.y; + right = rb.x; + bottom = rb.y; } void makeInvalid(); @@ -53,43 +64,36 @@ public: // a valid rectangle has a non negative width and height inline bool isValid() const { - return (width()>=0) && (height()>=0); + return (getWidth() >= 0) && (getHeight() >= 0); } // an empty rect has a zero width or height, or is invalid inline bool isEmpty() const { - return (width()<=0) || (height()<=0); - } - - inline void set(const Rect& rhs) { - operator = (rhs); + return (getWidth() <= 0) || (getHeight() <= 0); } // rectangle's width inline int32_t getWidth() const { - return right-left; + return right - left; } - + // rectangle's height inline int32_t getHeight() const { - return bottom-top; + return bottom - top; } inline Rect getBounds() const { - return Rect(right-left, bottom-top); + return Rect(right - left, bottom - top); } - inline int32_t width() const { return getWidth(); } - inline int32_t height() const { return getHeight(); } - void setLeftTop(const Point& lt) { left = lt.x; - top = lt.y; + top = lt.y; } void setRightBottom(const Point& rb) { right = rb.x; - bottom = rb.y; + bottom = rb.y; } // the following 4 functions return the 4 corners of the rect as Point @@ -120,6 +124,16 @@ public: // vectors. bool operator < (const Rect& rhs) const; + const Rect operator + (const Point& rhs) const; + const Rect operator - (const Point& rhs) const; + + Rect& operator += (const Point& rhs) { + return offsetBy(rhs.x, rhs.y); + } + Rect& operator -= (const Point& rhs) { + return offsetBy(-rhs.x, -rhs.y); + } + Rect& offsetToOrigin() { right -= left; bottom -= top; @@ -132,22 +146,11 @@ public: Rect& offsetBy(const Point& dp) { return offsetBy(dp.x, dp.y); } - Rect& operator += (const Point& rhs) { - return offsetBy(rhs.x, rhs.y); - } - Rect& operator -= (const Point& rhs) { - return offsetBy(-rhs.x, -rhs.y); - } - const Rect operator + (const Point& rhs) const; - const Rect operator - (const Point& rhs) const; - void translate(int32_t dx, int32_t dy) { // legacy, don't use. - offsetBy(dx, dy); - } + Rect& offsetTo(int32_t x, int32_t y); + Rect& offsetBy(int32_t x, int32_t y); - Rect& offsetTo(int32_t x, int32_t y); - Rect& offsetBy(int32_t x, int32_t y); - bool intersect(const Rect& with, Rect* result) const; + bool intersect(const Rect& with, Rect* result) const; // Create a new Rect by transforming this one using a graphics HAL // transform. This rectangle is defined in a coordinate space starting at @@ -156,6 +159,15 @@ public: // (height, width). Otherwise the output rectangle is in the same space as // the input. Rect transform(uint32_t xform, int32_t width, int32_t height) const; + + // this calculates (Region(*this) - exclude).bounds() efficiently + Rect reduce(const Rect& exclude) const; + + + // for backward compatibility + inline int32_t width() const { return getWidth(); } + inline int32_t height() const { return getHeight(); } + inline void set(const Rect& rhs) { operator = (rhs); } }; ANDROID_BASIC_TYPES_TRAITS(Rect) diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h index e189d0c..19c03d1 100644 --- a/include/utils/BitSet.h +++ b/include/utils/BitSet.h @@ -101,6 +101,20 @@ struct BitSet32 { inline bool operator== (const BitSet32& other) const { return value == other.value; } inline bool operator!= (const BitSet32& other) const { return value != other.value; } + inline BitSet32 operator& (const BitSet32& other) const { + return BitSet32(value & other.value); + } + inline BitSet32& operator&= (const BitSet32& other) { + value &= other.value; + return *this; + } + inline BitSet32 operator| (const BitSet32& other) const { + return BitSet32(value | other.value); + } + inline BitSet32& operator|= (const BitSet32& other) { + value |= other.value; + return *this; + } }; ANDROID_BASIC_TYPES_TRAITS(BitSet32) diff --git a/include/utils/Debug.h b/include/utils/Debug.h index d9ed32d..08893bd 100644 --- a/include/utils/Debug.h +++ b/include/utils/Debug.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ANDROID_DEBUG_H -#define ANDROID_DEBUG_H +#ifndef ANDROID_UTILS_DEBUG_H +#define ANDROID_UTILS_DEBUG_H #include <stdint.h> #include <sys/types.h> @@ -43,28 +43,6 @@ struct CompileTimeIfElse<false, LHS, RHS> { typedef RHS TYPE; }; #endif // --------------------------------------------------------------------------- - -#ifdef __cplusplus -extern "C" { -#endif - -const char* stringForIndent(int32_t indentLevel); - -typedef void (*debugPrintFunc)(void* cookie, const char* txt); - -void printTypeCode(uint32_t typeCode, - debugPrintFunc func = 0, void* cookie = 0); - -void printHexData(int32_t indent, const void *buf, size_t length, - size_t bytesPerLine=16, int32_t singleLineBytesCutoff=16, - size_t alignment=0, bool cArrayStyle=false, - debugPrintFunc func = 0, void* cookie = 0); - -#ifdef __cplusplus -} -#endif - -// --------------------------------------------------------------------------- }; // namespace android -#endif // ANDROID_DEBUG_H +#endif // ANDROID_UTILS_DEBUG_H diff --git a/include/utils/GenerationCache.h b/include/utils/GenerationCache.h deleted file mode 100644 index 40722d1..0000000 --- a/include/utils/GenerationCache.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef ANDROID_UTILS_GENERATION_CACHE_H -#define ANDROID_UTILS_GENERATION_CACHE_H - -#include <utils/KeyedVector.h> -#include <utils/RefBase.h> - -namespace android { - -/** - * GenerationCache callback used when an item is removed - */ -template<typename EntryKey, typename EntryValue> -class OnEntryRemoved { -public: - virtual ~OnEntryRemoved() { }; - virtual void operator()(EntryKey& key, EntryValue& value) = 0; -}; // class OnEntryRemoved - -template<typename EntryKey, typename EntryValue> -struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > { - Entry(const Entry<EntryKey, EntryValue>& e) : - key(e.key), value(e.value), - parent(e.parent), child(e.child) { } - Entry(const EntryKey& key, const EntryValue& value) : - key(key), value(value) { } - - EntryKey key; - EntryValue value; - - sp<Entry<EntryKey, EntryValue> > parent; // next older entry - sp<Entry<EntryKey, EntryValue> > child; // next younger entry -}; // struct Entry - -/** - * A LRU type cache - */ -template<typename K, typename V> -class GenerationCache { -public: - GenerationCache(uint32_t maxCapacity); - virtual ~GenerationCache(); - - enum Capacity { - kUnlimitedCapacity, - }; - - void setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener); - - size_t size() const; - - void clear(); - - bool contains(const K& key) const; - const K& getKeyAt(size_t index) const; - const V& getValueAt(size_t index) const; - - const V& get(const K& key); - bool put(const K& key, const V& value); - - void removeAt(ssize_t index); - bool remove(const K& key); - bool removeOldest(); - -private: - KeyedVector<K, sp<Entry<K, V> > > mCache; - uint32_t mMaxCapacity; - - OnEntryRemoved<K, V>* mListener; - - sp<Entry<K, V> > mOldest; - sp<Entry<K, V> > mYoungest; - - void attachToCache(const sp<Entry<K, V> >& entry); - void detachFromCache(const sp<Entry<K, V> >& entry); - - const V mNullValue; -}; // class GenerationCache - -template<typename K, typename V> -GenerationCache<K, V>::GenerationCache(uint32_t maxCapacity): mMaxCapacity(maxCapacity), - mListener(NULL), mNullValue(NULL) { -}; - -template<typename K, typename V> -GenerationCache<K, V>::~GenerationCache() { - clear(); -}; - -template<typename K, typename V> -uint32_t GenerationCache<K, V>::size() const { - return mCache.size(); -} - -/** - * Should be set by the user of the Cache so that the callback is called whenever an item is - * removed from the cache - */ -template<typename K, typename V> -void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K, V>* listener) { - mListener = listener; -} - -template<typename K, typename V> -void GenerationCache<K, V>::clear() { - if (mListener) { - for (uint32_t i = 0; i < mCache.size(); i++) { - sp<Entry<K, V> > entry = mCache.valueAt(i); - if (mListener) { - (*mListener)(entry->key, entry->value); - } - } - } - mCache.clear(); - mYoungest.clear(); - mOldest.clear(); -} - -template<typename K, typename V> -bool GenerationCache<K, V>::contains(const K& key) const { - return mCache.indexOfKey(key) >= 0; -} - -template<typename K, typename V> -const K& GenerationCache<K, V>::getKeyAt(size_t index) const { - return mCache.keyAt(index); -} - -template<typename K, typename V> -const V& GenerationCache<K, V>::getValueAt(size_t index) const { - return mCache.valueAt(index)->value; -} - -template<typename K, typename V> -const V& GenerationCache<K, V>::get(const K& key) { - ssize_t index = mCache.indexOfKey(key); - if (index >= 0) { - const sp<Entry<K, V> >& entry = mCache.valueAt(index); - detachFromCache(entry); - attachToCache(entry); - return entry->value; - } - - return mNullValue; -} - -template<typename K, typename V> -bool GenerationCache<K, V>::put(const K& key, const V& value) { - if (mMaxCapacity != kUnlimitedCapacity && mCache.size() >= mMaxCapacity) { - removeOldest(); - } - - ssize_t index = mCache.indexOfKey(key); - if (index < 0) { - sp<Entry<K, V> > entry = new Entry<K, V>(key, value); - mCache.add(key, entry); - attachToCache(entry); - return true; - } - - return false; -} - -template<typename K, typename V> -bool GenerationCache<K, V>::remove(const K& key) { - ssize_t index = mCache.indexOfKey(key); - if (index >= 0) { - removeAt(index); - return true; - } - - return false; -} - -template<typename K, typename V> -void GenerationCache<K, V>::removeAt(ssize_t index) { - sp<Entry<K, V> > entry = mCache.valueAt(index); - if (mListener) { - (*mListener)(entry->key, entry->value); - } - mCache.removeItemsAt(index, 1); - detachFromCache(entry); -} - -template<typename K, typename V> -bool GenerationCache<K, V>::removeOldest() { - if (mOldest.get()) { - ssize_t index = mCache.indexOfKey(mOldest->key); - if (index >= 0) { - removeAt(index); - return true; - } - ALOGE("GenerationCache: removeOldest failed to find the item in the cache " - "with the given key, but we know it must be in there. " - "Is the key comparator kaput?"); - } - - return false; -} - -template<typename K, typename V> -void GenerationCache<K, V>::attachToCache(const sp<Entry<K, V> >& entry) { - if (!mYoungest.get()) { - mYoungest = mOldest = entry; - } else { - entry->parent = mYoungest; - mYoungest->child = entry; - mYoungest = entry; - } -} - -template<typename K, typename V> -void GenerationCache<K, V>::detachFromCache(const sp<Entry<K, V> >& entry) { - if (entry->parent.get()) { - entry->parent->child = entry->child; - } else { - mOldest = entry->child; - } - - if (entry->child.get()) { - entry->child->parent = entry->parent; - } else { - mYoungest = entry->parent; - } - - entry->parent.clear(); - entry->child.clear(); -} - -}; // namespace android - -#endif // ANDROID_UTILS_GENERATION_CACHE_H diff --git a/include/utils/Looper.h b/include/utils/Looper.h index d4a0067..2e0651a 100644 --- a/include/utils/Looper.h +++ b/include/utils/Looper.h @@ -297,6 +297,13 @@ public: void removeMessages(const sp<MessageHandler>& handler, int what); /** + * Return whether this looper's thread is currently idling -- that is, whether it + * stopped waiting for more work to do. Note that this is intrinsically racy, since + * its state can change before you get the result back. + */ + bool isIdling() const; + + /** * Prepares a looper associated with the calling thread, and returns it. * If the thread already has a looper, it is returned. Otherwise, a new * one is created, associated with the thread, and returned. @@ -353,6 +360,10 @@ private: Vector<MessageEnvelope> mMessageEnvelopes; // guarded by mLock bool mSendingMessage; // guarded by mLock + // Whether we are currently waiting for work. Not protected by a lock, + // any use of it is racy anyway. + volatile bool mIdling; + int mEpollFd; // immutable // Locked list of file descriptor monitoring requests. diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h index 302b929..053bfaf 100644 --- a/include/utils/LruCache.h +++ b/include/utils/LruCache.h @@ -18,12 +18,19 @@ #define ANDROID_UTILS_LRU_CACHE_H #include <utils/BasicHashtable.h> -#include <utils/GenerationCache.h> #include <utils/UniquePtr.h> namespace android { -// OnEntryRemoved is defined in GenerationCache.h, but maybe should move here. +/** + * GenerationCache callback used when an item is removed + */ +template<typename EntryKey, typename EntryValue> +class OnEntryRemoved { +public: + virtual ~OnEntryRemoved() { }; + virtual void operator()(EntryKey& key, EntryValue& value) = 0; +}; // class OnEntryRemoved template <typename TKey, typename TValue> class LruCache { diff --git a/include/utils/String16.h b/include/utils/String16.h index fe06c57..d131bfc 100644 --- a/include/utils/String16.h +++ b/include/utils/String16.h @@ -41,7 +41,16 @@ class TextOutput; class String16 { public: + /* use String16(StaticLinkage) if you're statically linking against + * libutils and declaring an empty static String16, e.g.: + * + * static String16 sAStaticEmptyString(String16::kEmptyString); + * static String16 sAnotherStaticEmptyString(sAStaticEmptyString); + */ + enum StaticLinkage { kEmptyString }; + String16(); + explicit String16(StaticLinkage); String16(const String16& o); String16(const String16& o, size_t len, @@ -117,8 +126,6 @@ private: // require any change to the underlying SharedBuffer contents or reference count. ANDROID_TRIVIAL_MOVE_TRAIT(String16) -TextOutput& operator<<(TextOutput& to, const String16& val); - // --------------------------------------------------------------------------- // No user servicable parts below. diff --git a/include/utils/String8.h b/include/utils/String8.h index 335e7f1..ef59470 100644 --- a/include/utils/String8.h +++ b/include/utils/String8.h @@ -37,7 +37,16 @@ class TextOutput; class String8 { public: + /* use String8(StaticLinkage) if you're statically linking against + * libutils and declaring an empty static String8, e.g.: + * + * static String8 sAStaticEmptyString(String8::kEmptyString); + * static String8 sAnotherStaticEmptyString(sAStaticEmptyString); + */ + enum StaticLinkage { kEmptyString }; + String8(); + explicit String8(StaticLinkage); String8(const String8& o); explicit String8(const char* o); explicit String8(const char* o, size_t numChars); @@ -224,8 +233,6 @@ private: // require any change to the underlying SharedBuffer contents or reference count. ANDROID_TRIVIAL_MOVE_TRAIT(String8) -TextOutput& operator<<(TextOutput& to, const String16& val); - // --------------------------------------------------------------------------- // No user servicable parts below. diff --git a/include/utils/StringArray.h b/include/utils/StringArray.h deleted file mode 100644 index c244587..0000000 --- a/include/utils/StringArray.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -// -// Sortable array of strings. STL-ish, but STL-free. -// -#ifndef _LIBS_UTILS_STRING_ARRAY_H -#define _LIBS_UTILS_STRING_ARRAY_H - -#include <stdlib.h> -#include <string.h> - -namespace android { - -// -// An expanding array of strings. Add, get, sort, delete. -// -class StringArray { -public: - StringArray(); - virtual ~StringArray(); - - // - // Add a string. A copy of the string is made. - // - bool push_back(const char* str); - - // - // Delete an entry. - // - void erase(int idx); - - // - // Sort the array. - // - void sort(int (*compare)(const void*, const void*)); - - // - // Pass this to the sort routine to do an ascending alphabetical sort. - // - static int cmpAscendingAlpha(const void* pstr1, const void* pstr2); - - // - // Get the #of items in the array. - // - inline int size(void) const { return mCurrent; } - - // - // Return entry N. - // [should use operator[] here] - // - const char* getEntry(int idx) const { - return (unsigned(idx) >= unsigned(mCurrent)) ? NULL : mArray[idx]; - } - - // - // Set entry N to specified string. - // [should use operator[] here] - // - void setEntry(int idx, const char* str); - -private: - int mMax; - int mCurrent; - char** mArray; -}; - -}; // namespace android - -#endif // _LIBS_UTILS_STRING_ARRAY_H diff --git a/include/utils/StrongPointer.h b/include/utils/StrongPointer.h index 49fa3a8..aba9577 100644 --- a/include/utils/StrongPointer.h +++ b/include/utils/StrongPointer.h @@ -26,9 +26,6 @@ // --------------------------------------------------------------------------- namespace android { -class TextOutput; -TextOutput& printStrongPointer(TextOutput& to, const void* val); - template<typename T> class wp; // --------------------------------------------------------------------------- @@ -58,9 +55,8 @@ inline bool operator _op_ (const wp<U>& o) const { \ // --------------------------------------------------------------------------- -template <typename T> -class sp -{ +template<typename T> +class sp { public: inline sp() : m_ptr(0) { } @@ -110,92 +106,93 @@ private: #undef COMPARE -template <typename T> -TextOutput& operator<<(TextOutput& to, const sp<T>& val); - // --------------------------------------------------------------------------- // No user serviceable parts below here. template<typename T> sp<T>::sp(T* other) -: m_ptr(other) - { - if (other) other->incStrong(this); - } + : m_ptr(other) { + if (other) + other->incStrong(this); +} template<typename T> sp<T>::sp(const sp<T>& other) -: m_ptr(other.m_ptr) - { - if (m_ptr) m_ptr->incStrong(this); - } + : m_ptr(other.m_ptr) { + if (m_ptr) + m_ptr->incStrong(this); +} template<typename T> template<typename U> -sp<T>::sp(U* other) : m_ptr(other) -{ - if (other) ((T*)other)->incStrong(this); +sp<T>::sp(U* other) + : m_ptr(other) { + if (other) + ((T*) other)->incStrong(this); } template<typename T> template<typename U> sp<T>::sp(const sp<U>& other) -: m_ptr(other.m_ptr) - { - if (m_ptr) m_ptr->incStrong(this); - } + : m_ptr(other.m_ptr) { + if (m_ptr) + m_ptr->incStrong(this); +} template<typename T> -sp<T>::~sp() -{ - if (m_ptr) m_ptr->decStrong(this); +sp<T>::~sp() { + if (m_ptr) + m_ptr->decStrong(this); } template<typename T> -sp<T>& sp<T>::operator = (const sp<T>& other) { +sp<T>& sp<T>::operator =(const sp<T>& other) { T* otherPtr(other.m_ptr); - if (otherPtr) otherPtr->incStrong(this); - if (m_ptr) m_ptr->decStrong(this); + if (otherPtr) + otherPtr->incStrong(this); + if (m_ptr) + m_ptr->decStrong(this); m_ptr = otherPtr; return *this; } template<typename T> -sp<T>& sp<T>::operator = (T* other) -{ - if (other) other->incStrong(this); - if (m_ptr) m_ptr->decStrong(this); +sp<T>& sp<T>::operator =(T* other) { + if (other) + other->incStrong(this); + if (m_ptr) + m_ptr->decStrong(this); m_ptr = other; return *this; } template<typename T> template<typename U> -sp<T>& sp<T>::operator = (const sp<U>& other) -{ +sp<T>& sp<T>::operator =(const sp<U>& other) { T* otherPtr(other.m_ptr); - if (otherPtr) otherPtr->incStrong(this); - if (m_ptr) m_ptr->decStrong(this); + if (otherPtr) + otherPtr->incStrong(this); + if (m_ptr) + m_ptr->decStrong(this); m_ptr = otherPtr; return *this; } template<typename T> template<typename U> -sp<T>& sp<T>::operator = (U* other) -{ - if (other) ((T*)other)->incStrong(this); - if (m_ptr) m_ptr->decStrong(this); +sp<T>& sp<T>::operator =(U* other) { + if (other) + ((T*) other)->incStrong(this); + if (m_ptr) + m_ptr->decStrong(this); m_ptr = other; return *this; } -template<typename T> -void sp<T>::force_set(T* other) -{ +template<typename T> +void sp<T>::force_set(T* other) { other->forceIncStrong(this); m_ptr = other; } template<typename T> -void sp<T>::clear() -{ +void sp<T>::clear() { if (m_ptr) { m_ptr->decStrong(this); m_ptr = 0; @@ -207,12 +204,6 @@ void sp<T>::set_pointer(T* ptr) { m_ptr = ptr; } -template <typename T> -inline TextOutput& operator<<(TextOutput& to, const sp<T>& val) -{ - return printStrongPointer(to, val.get()); -} - }; // namespace android // --------------------------------------------------------------------------- diff --git a/include/utils/SystemClock.h b/include/utils/SystemClock.h index d75264c..01db340 100644 --- a/include/utils/SystemClock.h +++ b/include/utils/SystemClock.h @@ -22,7 +22,6 @@ namespace android { -int setCurrentTimeMillis(int64_t millis); int64_t uptimeMillis(); int64_t elapsedRealtime(); int64_t elapsedRealtimeNano(); diff --git a/include/utils/Timers.h b/include/utils/Timers.h index 92f66c9..d015421 100644 --- a/include/utils/Timers.h +++ b/include/utils/Timers.h @@ -103,43 +103,4 @@ int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime); } // extern "C" #endif -// ------------------------------------------------------------------ -// C++ API - -#ifdef __cplusplus - -namespace android { -/* - * Time the duration of something. - * - * Includes some timeval manipulation functions. - */ -class DurationTimer { -public: - DurationTimer() {} - ~DurationTimer() {} - - // Start the timer. - void start(); - // Stop the timer. - void stop(); - // Get the duration in microseconds. - long long durationUsecs() const; - - // Subtract two timevals. Returns the difference (ptv1-ptv2) in - // microseconds. - static long long subtractTimevals(const struct timeval* ptv1, - const struct timeval* ptv2); - - // Add the specified amount of time to the timeval. - static void addToTimeval(struct timeval* ptv, long usec); - -private: - struct timeval mStartWhen; - struct timeval mStopWhen; -}; - -}; // android -#endif // def __cplusplus - #endif // _LIBS_UTILS_TIMERS_H diff --git a/include/utils/Trace.h b/include/utils/Trace.h index 49578c4..6ee343d 100644 --- a/include/utils/Trace.h +++ b/include/utils/Trace.h @@ -17,6 +17,8 @@ #ifndef ANDROID_TRACE_H #define ANDROID_TRACE_H +#ifdef HAVE_ANDROID_OS + #include <fcntl.h> #include <stdint.h> #include <stdio.h> @@ -57,4 +59,11 @@ private: }; // namespace android +#else // HAVE_ANDROID_OS + +#define ATRACE_NAME(...) +#define ATRACE_CALL() + +#endif // HAVE_ANDROID_OS + #endif // ANDROID_TRACE_H diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h index 9bc50e6..21ad71c 100644 --- a/include/utils/VectorImpl.h +++ b/include/utils/VectorImpl.h @@ -105,16 +105,6 @@ protected: virtual void do_splat(void* dest, const void* item, size_t num) const = 0; virtual void do_move_forward(void* dest, const void* from, size_t num) const = 0; virtual void do_move_backward(void* dest, const void* from, size_t num) const = 0; - - // take care of FBC... - virtual void reservedVectorImpl1(); - virtual void reservedVectorImpl2(); - virtual void reservedVectorImpl3(); - virtual void reservedVectorImpl4(); - virtual void reservedVectorImpl5(); - virtual void reservedVectorImpl6(); - virtual void reservedVectorImpl7(); - virtual void reservedVectorImpl8(); private: void* _grow(size_t where, size_t amount); @@ -166,16 +156,6 @@ public: protected: virtual int do_compare(const void* lhs, const void* rhs) const = 0; - // take care of FBC... - virtual void reservedSortedVectorImpl1(); - virtual void reservedSortedVectorImpl2(); - virtual void reservedSortedVectorImpl3(); - virtual void reservedSortedVectorImpl4(); - virtual void reservedSortedVectorImpl5(); - virtual void reservedSortedVectorImpl6(); - virtual void reservedSortedVectorImpl7(); - virtual void reservedSortedVectorImpl8(); - private: ssize_t _indexOrderOf(const void* item, size_t* order = 0) const; diff --git a/include/utils/WorkQueue.h b/include/utils/WorkQueue.h deleted file mode 100644 index e3c75b2..0000000 --- a/include/utils/WorkQueue.h +++ /dev/null @@ -1,119 +0,0 @@ -/*] - * Copyright (C) 2012 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. - */ - -#ifndef _LIBS_UTILS_WORK_QUEUE_H -#define _LIBS_UTILS_WORK_QUEUE_H - -#include <utils/Errors.h> -#include <utils/Vector.h> -#include <utils/threads.h> - -namespace android { - -/* - * A threaded work queue. - * - * This class is designed to make it easy to run a bunch of isolated work - * units in parallel, using up to the specified number of threads. - * To use it, write a loop to post work units to the work queue, then synchronize - * on the queue at the end. - */ -class WorkQueue { -public: - class WorkUnit { - public: - WorkUnit() { } - virtual ~WorkUnit() { } - - /* - * Runs the work unit. - * If the result is 'true' then the work queue continues scheduling work as usual. - * If the result is 'false' then the work queue is canceled. - */ - virtual bool run() = 0; - }; - - /* Creates a work queue with the specified maximum number of work threads. */ - WorkQueue(size_t maxThreads, bool canCallJava = true); - - /* Destroys the work queue. - * Cancels pending work and waits for all remaining threads to complete. - */ - ~WorkQueue(); - - /* Posts a work unit to run later. - * If the work queue has been canceled or is already finished, returns INVALID_OPERATION - * and does not take ownership of the work unit (caller must destroy it itself). - * Otherwise, returns OK and takes ownership of the work unit (the work queue will - * destroy it automatically). - * - * For flow control, this method blocks when the size of the pending work queue is more - * 'backlog' times the number of threads. This condition reduces the rate of entry into - * the pending work queue and prevents it from growing much more rapidly than the - * work threads can actually handle. - * - * If 'backlog' is 0, then no throttle is applied. - */ - status_t schedule(WorkUnit* workUnit, size_t backlog = 2); - - /* Cancels all pending work. - * If the work queue is already finished, returns INVALID_OPERATION. - * If the work queue is already canceled, returns OK and does nothing else. - * Otherwise, returns OK, discards all pending work units and prevents additional - * work units from being scheduled. - * - * Call finish() after cancel() to wait for all remaining work to complete. - */ - status_t cancel(); - - /* Waits for all work to complete. - * If the work queue is already finished, returns INVALID_OPERATION. - * Otherwise, waits for all work to complete and returns OK. - */ - status_t finish(); - -private: - class WorkThread : public Thread { - public: - WorkThread(WorkQueue* workQueue, bool canCallJava); - virtual ~WorkThread(); - - private: - virtual bool threadLoop(); - - WorkQueue* const mWorkQueue; - }; - - status_t cancelLocked(); - bool threadLoop(); // called from each work thread - - const size_t mMaxThreads; - const bool mCanCallJava; - - Mutex mLock; - Condition mWorkChangedCondition; - Condition mWorkDequeuedCondition; - - bool mCanceled; - bool mFinished; - size_t mIdleThreads; - Vector<sp<WorkThread> > mWorkThreads; - Vector<WorkUnit*> mWorkUnits; -}; - -}; // namespace android - -#endif // _LIBS_UTILS_WORK_QUEUE_H diff --git a/include/utils/ZipFileCRO.h b/include/utils/ZipFileCRO.h deleted file mode 100644 index 3e42a95..0000000 --- a/include/utils/ZipFileCRO.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -// -// C API for ead-only access to Zip archives, with minimal heap allocation. -// -#ifndef __LIBS_ZIPFILECRO_H -#define __LIBS_ZIPFILECRO_H - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include <utils/Compat.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Trivial typedef to ensure that ZipFileCRO is not treated as a simple integer. - */ -typedef void* ZipFileCRO; - -/* - * Trivial typedef to ensure that ZipEntryCRO is not treated as a simple - * integer. We use NULL to indicate an invalid value. - */ -typedef void* ZipEntryCRO; - -extern ZipFileCRO ZipFileXRO_open(const char* path); - -extern void ZipFileCRO_destroy(ZipFileCRO zip); - -extern ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zip, - const char* fileName); - -extern bool ZipFileCRO_getEntryInfo(ZipFileCRO zip, ZipEntryCRO entry, - int* pMethod, size_t* pUncompLen, - size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32); - -extern bool ZipFileCRO_uncompressEntry(ZipFileCRO zip, ZipEntryCRO entry, int fd); - -#ifdef __cplusplus -} -#endif - -#endif /*__LIBS_ZIPFILECRO_H*/ diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h deleted file mode 100644 index 547e36a..0000000 --- a/include/utils/ZipFileRO.h +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -/* - * Read-only access to Zip archives, with minimal heap allocation. - * - * This is similar to the more-complete ZipFile class, but no attempt - * has been made to make them interchangeable. This class operates under - * a very different set of assumptions and constraints. - * - * One such assumption is that if you're getting file descriptors for - * use with this class as a child of a fork() operation, you must be on - * a pread() to guarantee correct operation. This is because pread() can - * atomically read at a file offset without worrying about a lock around an - * lseek() + read() pair. - */ -#ifndef __LIBS_ZIPFILERO_H -#define __LIBS_ZIPFILERO_H - -#include <utils/Compat.h> -#include <utils/Errors.h> -#include <utils/FileMap.h> -#include <utils/threads.h> - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <time.h> - -namespace android { - -/* - * Trivial typedef to ensure that ZipEntryRO is not treated as a simple - * integer. We use NULL to indicate an invalid value. - */ -typedef void* ZipEntryRO; - -/* - * Open a Zip archive for reading. - * - * We want "open" and "find entry by name" to be fast operations, and we - * want to use as little memory as possible. We memory-map the file, - * and load a hash table with pointers to the filenames (which aren't - * null-terminated). The other fields are at a fixed offset from the - * filename, so we don't need to extract those (but we do need to byte-read - * and endian-swap them every time we want them). - * - * To speed comparisons when doing a lookup by name, we could make the mapping - * "private" (copy-on-write) and null-terminate the filenames after verifying - * the record structure. However, this requires a private mapping of - * every page that the Central Directory touches. Easier to tuck a copy - * of the string length into the hash table entry. - * - * NOTE: If this is used on file descriptors inherited from a fork() operation, - * you must be on a platform that implements pread() to guarantee correctness - * on the shared file descriptors. - */ -class ZipFileRO { -public: - ZipFileRO() - : mFd(-1), mFileName(NULL), mFileLength(-1), - mDirectoryMap(NULL), - mNumEntries(-1), mDirectoryOffset(-1), - mHashTableSize(-1), mHashTable(NULL) - {} - - ~ZipFileRO(); - - /* - * Open an archive. - */ - status_t open(const char* zipFileName); - - /* - * Find an entry, by name. Returns the entry identifier, or NULL if - * not found. - * - * If two entries have the same name, one will be chosen at semi-random. - */ - ZipEntryRO findEntryByName(const char* fileName) const; - - /* - * Return the #of entries in the Zip archive. - */ - int getNumEntries(void) const { - return mNumEntries; - } - - /* - * Return the Nth entry. Zip file entries are not stored in sorted - * order, and updated entries may appear at the end, so anyone walking - * the archive needs to avoid making ordering assumptions. We take - * that further by returning the Nth non-empty entry in the hash table - * rather than the Nth entry in the archive. - * - * Valid values are [0..numEntries). - * - * [This is currently O(n). If it needs to be fast we can allocate an - * additional data structure or provide an iterator interface.] - */ - ZipEntryRO findEntryByIndex(int idx) const; - - /* - * Copy the filename into the supplied buffer. Returns 0 on success, - * -1 if "entry" is invalid, or the filename length if it didn't fit. The - * length, and the returned string, include the null-termination. - */ - int getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) const; - - /* - * Get the vital stats for an entry. Pass in NULL pointers for anything - * you don't need. - * - * "*pOffset" holds the Zip file offset of the entry's data. - * - * Returns "false" if "entry" is bogus or if the data in the Zip file - * appears to be bad. - */ - bool getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, - size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const; - - /* - * Create a new FileMap object that maps a subset of the archive. For - * an uncompressed entry this effectively provides a pointer to the - * actual data, for a compressed entry this provides the input buffer - * for inflate(). - */ - FileMap* createEntryFileMap(ZipEntryRO entry) const; - - /* - * Uncompress the data into a buffer. Depending on the compression - * format, this is either an "inflate" operation or a memcpy. - * - * Use "uncompLen" from getEntryInfo() to determine the required - * buffer size. - * - * Returns "true" on success. - */ - bool uncompressEntry(ZipEntryRO entry, void* buffer) const; - - /* - * Uncompress the data to an open file descriptor. - */ - bool uncompressEntry(ZipEntryRO entry, int fd) const; - - /* Zip compression methods we support */ - enum { - kCompressStored = 0, // no compression - kCompressDeflated = 8, // standard deflate - }; - - /* - * Utility function: uncompress deflated data, buffer to buffer. - */ - static bool inflateBuffer(void* outBuf, const void* inBuf, - size_t uncompLen, size_t compLen); - - /* - * Utility function: uncompress deflated data, buffer to fd. - */ - static bool inflateBuffer(int fd, const void* inBuf, - size_t uncompLen, size_t compLen); - - /* - * Utility function to convert ZIP's time format to a timespec struct. - */ - static inline void zipTimeToTimespec(long when, struct tm* timespec) { - const long date = when >> 16; - timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980 - timespec->tm_mon = (date >> 5) & 0x0F; - timespec->tm_mday = date & 0x1F; - - timespec->tm_hour = (when >> 11) & 0x1F; - timespec->tm_min = (when >> 5) & 0x3F; - timespec->tm_sec = (when & 0x1F) << 1; - } - - /* - * Some basic functions for raw data manipulation. "LE" means - * Little Endian. - */ - static inline unsigned short get2LE(const unsigned char* buf) { - return buf[0] | (buf[1] << 8); - } - static inline unsigned long get4LE(const unsigned char* buf) { - return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); - } - -private: - /* these are private and not defined */ - ZipFileRO(const ZipFileRO& src); - ZipFileRO& operator=(const ZipFileRO& src); - - /* locate and parse the central directory */ - bool mapCentralDirectory(void); - - /* parse the archive, prepping internal structures */ - bool parseZipArchive(void); - - /* add a new entry to the hash table */ - void addToHash(const char* str, int strLen, unsigned int hash); - - /* compute string hash code */ - static unsigned int computeHash(const char* str, int len); - - /* convert a ZipEntryRO back to a hash table index */ - int entryToIndex(const ZipEntryRO entry) const; - - /* - * One entry in the hash table. - */ - typedef struct HashEntry { - const char* name; - unsigned short nameLen; - //unsigned int hash; - } HashEntry; - - /* open Zip archive */ - int mFd; - - /* Lock for handling the file descriptor (seeks, etc) */ - mutable Mutex mFdLock; - - /* zip file name */ - char* mFileName; - - /* length of file */ - size_t mFileLength; - - /* mapped file */ - FileMap* mDirectoryMap; - - /* number of entries in the Zip archive */ - int mNumEntries; - - /* CD directory offset in the Zip archive */ - off64_t mDirectoryOffset; - - /* - * We know how many entries are in the Zip archive, so we have a - * fixed-size hash table. We probe for an empty slot. - */ - int mHashTableSize; - HashEntry* mHashTable; -}; - -}; // namespace android - -#endif /*__LIBS_ZIPFILERO_H*/ diff --git a/include/utils/ZipUtils.h b/include/utils/ZipUtils.h deleted file mode 100644 index 42c42b6..0000000 --- a/include/utils/ZipUtils.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -// -// Miscellaneous zip/gzip utility functions. -// -#ifndef __LIBS_ZIPUTILS_H -#define __LIBS_ZIPUTILS_H - -#include <stdio.h> - -namespace android { - -/* - * Container class for utility functions, primarily for namespace reasons. - */ -class ZipUtils { -public: - /* - * General utility function for uncompressing "deflate" data from a file - * to a buffer. - */ - static bool inflateToBuffer(int fd, void* buf, long uncompressedLen, - long compressedLen); - static bool inflateToBuffer(FILE* fp, void* buf, long uncompressedLen, - long compressedLen); - - /* - * Someday we might want to make this generic and handle bzip2 ".bz2" - * files too. - * - * We could declare gzip to be a sub-class of zip that has exactly - * one always-compressed entry, but we currently want to treat Zip - * and gzip as distinct, so there's no value. - * - * The zlib library has some gzip utilities, but it has no interface - * for extracting the uncompressed length of the file (you do *not* - * want to gzseek to the end). - * - * Pass in a seeked file pointer for the gzip file. If this is a gzip - * file, we set our return values appropriately and return "true" with - * the file seeked to the start of the compressed data. - */ - static bool examineGzip(FILE* fp, int* pCompressionMethod, - long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32); - -private: - ZipUtils() {} - ~ZipUtils() {} -}; - -}; // namespace android - -#endif /*__LIBS_ZIPUTILS_H*/ diff --git a/include/utils/misc.h b/include/utils/misc.h index f1aa432..6cccec3 100644 --- a/include/utils/misc.h +++ b/include/utils/misc.h @@ -20,7 +20,6 @@ #ifndef _LIBS_UTILS_MISC_H #define _LIBS_UTILS_MISC_H -#include <sys/time.h> #include <utils/Endian.h> /* get #of elements in a static array */ @@ -30,26 +29,6 @@ namespace android { -/* - * Some utility functions for working with files. These could be made - * part of a "File" class. - */ -typedef enum FileType { - kFileTypeUnknown = 0, - kFileTypeNonexistent, // i.e. ENOENT - kFileTypeRegular, - kFileTypeDirectory, - kFileTypeCharDev, - kFileTypeBlockDev, - kFileTypeFifo, - kFileTypeSymlink, - kFileTypeSocket, -} FileType; -/* get the file's type; follows symlinks */ -FileType getFileType(const char* fileName); -/* get the file's modification date; returns -1 w/errno set on failure */ -time_t getFileModDate(const char* fileName); - typedef void (*sysprop_change_callback)(void); void add_sysprop_change_callback(sysprop_change_callback cb, int priority); void report_sysprop_change(); diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk index 994d3db..4c8820e 100644 --- a/libs/binder/Android.mk +++ b/libs/binder/Android.mk @@ -17,6 +17,8 @@ sources := \ AppOpsManager.cpp \ Binder.cpp \ BpBinder.cpp \ + BufferedTextOutput.cpp \ + Debug.cpp \ IAppOpsCallback.cpp \ IAppOpsService.cpp \ IInterface.cpp \ @@ -30,7 +32,8 @@ sources := \ Parcel.cpp \ PermissionCache.cpp \ ProcessState.cpp \ - Static.cpp + Static.cpp \ + TextOutput.cpp \ LOCAL_PATH:= $(call my-dir) diff --git a/libs/utils/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp index 989662e..2d493c1 100644 --- a/libs/utils/BufferedTextOutput.cpp +++ b/libs/binder/BufferedTextOutput.cpp @@ -14,16 +14,16 @@ * limitations under the License. */ -#include <utils/BufferedTextOutput.h> +#include <binder/BufferedTextOutput.h> +#include <binder/Debug.h> #include <utils/Atomic.h> -#include <utils/Debug.h> #include <utils/Log.h> #include <utils/RefBase.h> #include <utils/Vector.h> #include <cutils/threads.h> -#include <private/utils/Static.h> +#include <private/binder/Static.h> #include <stdio.h> #include <stdlib.h> diff --git a/libs/utils/Debug.cpp b/libs/binder/Debug.cpp index e8ac983..a8b6e83 100644 --- a/libs/utils/Debug.cpp +++ b/libs/binder/Debug.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <utils/Debug.h> +#include <binder/Debug.h> #include <utils/misc.h> @@ -70,20 +70,6 @@ static char* appendhexnum(uint32_t val, char* out) return out; } -static inline char makeupperhexdigit(uint32_t val) -{ - return "0123456789ABCDEF"[val&0xF]; -} - -static char* appendupperhexnum(uint32_t val, char* out) -{ - for( int32_t i=28; i>=0; i-=4 ) { - *out++ = makeupperhexdigit( val>>i ); - } - *out = 0; - return out; -} - static char* appendcharornum(char c, char* out, bool skipzero = true) { if (skipzero && c == 0) return out; diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 2ffa927..28b74ba 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -20,10 +20,11 @@ #include <binder/Binder.h> #include <binder/BpBinder.h> +#include <binder/TextOutput.h> + #include <cutils/sched_policy.h> #include <utils/Debug.h> #include <utils/Log.h> -#include <utils/TextOutput.h> #include <utils/threads.h> #include <private/binder/binder_module.h> diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index c7bdcbc..359742c 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -22,12 +22,13 @@ #include <binder/IPCThreadState.h> #include <binder/Binder.h> #include <binder/BpBinder.h> -#include <utils/Debug.h> #include <binder/ProcessState.h> +#include <binder/TextOutput.h> + +#include <utils/Debug.h> #include <utils/Log.h> #include <utils/String8.h> #include <utils/String16.h> -#include <utils/TextOutput.h> #include <utils/misc.h> #include <utils/Flattenable.h> #include <cutils/ashmem.h> diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp index 12b0308..2062692 100644 --- a/libs/binder/Static.cpp +++ b/libs/binder/Static.cpp @@ -19,30 +19,76 @@ #include <private/binder/Static.h> +#include <binder/BufferedTextOutput.h> #include <binder/IPCThreadState.h> #include <utils/Log.h> namespace android { +// ------------ Text output streams + +Vector<int32_t> gTextBuffers; + +class LogTextOutput : public BufferedTextOutput +{ +public: + LogTextOutput() : BufferedTextOutput(MULTITHREADED) { } + virtual ~LogTextOutput() { }; + +protected: + virtual status_t writeLines(const struct iovec& vec, size_t N) + { + //android_writevLog(&vec, N); <-- this is now a no-op + if (N != 1) ALOGI("WARNING: writeLines N=%zu\n", N); + ALOGI("%.*s", (int)vec.iov_len, (const char*) vec.iov_base); + return NO_ERROR; + } +}; + +class FdTextOutput : public BufferedTextOutput +{ +public: + FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { } + virtual ~FdTextOutput() { }; + +protected: + virtual status_t writeLines(const struct iovec& vec, size_t N) + { + writev(mFD, &vec, N); + return NO_ERROR; + } + +private: + int mFD; +}; + +static LogTextOutput gLogTextOutput; +static FdTextOutput gStdoutTextOutput(STDOUT_FILENO); +static FdTextOutput gStderrTextOutput(STDERR_FILENO); + +TextOutput& alog(gLogTextOutput); +TextOutput& aout(gStdoutTextOutput); +TextOutput& aerr(gStderrTextOutput); + // ------------ ProcessState.cpp Mutex gProcessMutex; sp<ProcessState> gProcess; -class LibUtilsIPCtStatics +class LibBinderIPCtStatics { public: - LibUtilsIPCtStatics() + LibBinderIPCtStatics() { } - ~LibUtilsIPCtStatics() + ~LibBinderIPCtStatics() { IPCThreadState::shutdown(); } }; -static LibUtilsIPCtStatics gIPCStatics; +static LibBinderIPCtStatics gIPCStatics; // ------------ ServiceManager.cpp diff --git a/libs/utils/TextOutput.cpp b/libs/binder/TextOutput.cpp index e04823d..db3e858 100644 --- a/libs/utils/TextOutput.cpp +++ b/libs/binder/TextOutput.cpp @@ -14,9 +14,12 @@ * limitations under the License. */ -#include <utils/TextOutput.h> +#include <binder/TextOutput.h> -#include <utils/Debug.h> +#include <binder/Debug.h> + +#include <utils/String8.h> +#include <utils/String16.h> #include <stdio.h> #include <stdlib.h> @@ -119,6 +122,18 @@ TextOutput& operator<<(TextOutput& to, const void* val) return to; } +TextOutput& operator<<(TextOutput& to, const String8& val) +{ + to << val.string(); + return to; +} + +TextOutput& operator<<(TextOutput& to, const String16& val) +{ + to << String8(val).string(); + return to; +} + static void textOutputPrinter(void* cookie, const char* txt) { ((TextOutput*)cookie)->print(txt, strlen(txt)); diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 7db1b84..ba04bdf 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -82,9 +82,9 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, Mutex::Autolock _l(mMutex); - err = addReleaseFenceLocked(item.mBuf, releaseFence); + err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence); - err = releaseBufferLocked(item.mBuf, EGL_NO_DISPLAY, + err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err != OK) { BI_LOGE("Failed to release buffer: %s (%d)", diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index b4c7231..0dab864 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -178,12 +178,10 @@ status_t BufferQueue::setBufferCount(int bufferCount) { } // here we're guaranteed that the client doesn't have dequeued buffers - // and will release all of its buffer references. - // - // XXX: Should this use drainQueueAndFreeBuffersLocked instead? + // and will release all of its buffer references. We don't clear the + // queue, however, so currently queued buffers still get displayed. freeAllBuffersLocked(); mOverrideMaxBufferCount = bufferCount; - mBufferHasBeenQueued = false; mDequeueCondition.broadcast(); listener = mConsumerListener; } // scope for lock @@ -418,6 +416,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, return NO_INIT; } + mSlots[*outBuf].mFrameNumber = ~0; mSlots[*outBuf].mGraphicBuffer = graphicBuffer; } } @@ -435,7 +434,8 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, eglDestroySyncKHR(dpy, eglFence); } - ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, + ST_LOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outBuf, + mSlots[*outBuf].mFrameNumber, mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); return returnFlags; @@ -491,15 +491,22 @@ status_t BufferQueue::queueBuffer(int buf, return BAD_VALUE; } - ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x " - "scale=%s", - buf, timestamp, crop.left, crop.top, crop.right, crop.bottom, - transform, scalingModeName(scalingMode)); + switch (scalingMode) { + case NATIVE_WINDOW_SCALING_MODE_FREEZE: + case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: + case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: + case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: + break; + default: + ST_LOGE("unknown scaling mode: %d", scalingMode); + return -EINVAL; + } sp<ConsumerListener> listener; { // scope for the lock Mutex::Autolock lock(mMutex); + if (mAbandoned) { ST_LOGE("queueBuffer: BufferQueue has been abandoned!"); return NO_INIT; @@ -519,6 +526,12 @@ status_t BufferQueue::queueBuffer(int buf, return -EINVAL; } + ST_LOGV("queueBuffer: slot=%d/%llu time=%#llx crop=[%d,%d,%d,%d] " + "tr=%#x scale=%s", + buf, mFrameCounter + 1, timestamp, + crop.left, crop.top, crop.right, crop.bottom, + transform, scalingModeName(scalingMode)); + const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer); Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); Rect croppedCrop; @@ -529,9 +542,25 @@ status_t BufferQueue::queueBuffer(int buf, return -EINVAL; } + mSlots[buf].mFence = fence; + mSlots[buf].mBufferState = BufferSlot::QUEUED; + mFrameCounter++; + mSlots[buf].mFrameNumber = mFrameCounter; + + BufferItem item; + item.mAcquireCalled = mSlots[buf].mAcquireCalled; + item.mGraphicBuffer = mSlots[buf].mGraphicBuffer; + item.mCrop = crop; + item.mTransform = transform; + item.mScalingMode = scalingMode; + item.mTimestamp = timestamp; + item.mFrameNumber = mFrameCounter; + item.mBuf = buf; + item.mFence = fence; + if (mSynchronousMode) { // In synchronous mode we queue all buffers in a FIFO. - mQueue.push_back(buf); + mQueue.push_back(item); // Synchronous mode always signals that an additional frame should // be consumed. @@ -539,7 +568,7 @@ status_t BufferQueue::queueBuffer(int buf, } else { // In asynchronous mode we only keep the most recent buffer. if (mQueue.empty()) { - mQueue.push_back(buf); + mQueue.push_back(item); // Asynchronous mode only signals that a frame should be // consumed if no previous frame was pending. If a frame were @@ -547,34 +576,15 @@ status_t BufferQueue::queueBuffer(int buf, listener = mConsumerListener; } else { Fifo::iterator front(mQueue.begin()); - // buffer currently queued is freed - mSlots[*front].mBufferState = BufferSlot::FREE; + // buffer slot currently queued is marked free if still tracked + if (stillTracking(front)) { + mSlots[front->mBuf].mBufferState = BufferSlot::FREE; + } // and we record the new buffer index in the queued list - *front = buf; + *front = item; } } - mSlots[buf].mTimestamp = timestamp; - mSlots[buf].mCrop = crop; - mSlots[buf].mTransform = transform; - mSlots[buf].mFence = fence; - - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - break; - default: - ST_LOGE("unknown scaling mode: %d (ignoring)", scalingMode); - scalingMode = mSlots[buf].mScalingMode; - break; - } - - mSlots[buf].mBufferState = BufferSlot::QUEUED; - mSlots[buf].mScalingMode = scalingMode; - mFrameCounter++; - mSlots[buf].mFrameNumber = mFrameCounter; - mBufferHasBeenQueued = true; mDequeueCondition.broadcast(); @@ -707,36 +717,36 @@ status_t BufferQueue::disconnect(int api) { return err; } -void BufferQueue::dump(String8& result) const -{ - char buffer[1024]; - BufferQueue::dump(result, "", buffer, 1024); +void BufferQueue::dump(String8& result) const { + BufferQueue::dump(result, ""); } -void BufferQueue::dump(String8& result, const char* prefix, - char* buffer, size_t SIZE) const -{ +void BufferQueue::dump(String8& result, const char* prefix) const { Mutex::Autolock _l(mMutex); String8 fifo; int fifoSize = 0; Fifo::const_iterator i(mQueue.begin()); while (i != mQueue.end()) { - snprintf(buffer, SIZE, "%02d ", *i++); - fifoSize++; - fifo.append(buffer); + fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], " + "xform=0x%02x, time=%#llx, scale=%s\n", + i->mBuf, i->mGraphicBuffer.get(), + i->mCrop.left, i->mCrop.top, i->mCrop.right, + i->mCrop.bottom, i->mTransform, i->mTimestamp, + scalingModeName(i->mScalingMode) + ); + i++; + fifoSize++; } int maxBufferCount = getMaxBufferCountLocked(); - snprintf(buffer, SIZE, + result.appendFormat( "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", prefix, maxBufferCount, mSynchronousMode, mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint, fifoSize, fifo.string()); - result.append(buffer); - struct { const char * operator()(int state) const { @@ -752,25 +762,19 @@ void BufferQueue::dump(String8& result, const char* prefix, for (int i=0 ; i<maxBufferCount ; i++) { const BufferSlot& slot(mSlots[i]); - snprintf(buffer, SIZE, - "%s%s[%02d] " - "state=%-8s, crop=[%d,%d,%d,%d], " - "xform=0x%02x, time=%#llx, scale=%s", + result.appendFormat( + "%s%s[%02d:%p] state=%-8s", prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, - stateName(slot.mBufferState), - slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, - slot.mCrop.bottom, slot.mTransform, slot.mTimestamp, - scalingModeName(slot.mScalingMode) + slot.mGraphicBuffer.get(), + stateName(slot.mBufferState) ); - result.append(buffer); const sp<GraphicBuffer>& buf(slot.mGraphicBuffer); if (buf != NULL) { - snprintf(buffer, SIZE, + result.appendFormat( ", %p [%4ux%4u:%4u,%3X]", buf->handle, buf->width, buf->height, buf->stride, buf->format); - result.append(buffer); } result.append("\n"); } @@ -795,9 +799,8 @@ void BufferQueue::freeBufferLocked(int slot) { } void BufferQueue::freeAllBuffersLocked() { - ALOGW_IF(!mQueue.isEmpty(), - "freeAllBuffersLocked called but mQueue is not empty"); - mQueue.clear(); + ALOGD_IF(!mQueue.isEmpty(), + "freeAllBuffersLocked called with non-empty mQueue"); mBufferHasBeenQueued = false; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { freeBufferLocked(i); @@ -829,27 +832,27 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) { // deep, while in synchronous mode we use the oldest buffer. if (!mQueue.empty()) { Fifo::iterator front(mQueue.begin()); - int buf = *front; - + int buf = front->mBuf; + *buffer = *front; ATRACE_BUFFER_INDEX(buf); - if (mSlots[buf].mAcquireCalled) { + ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }", + front->mBuf, front->mFrameNumber, + front->mGraphicBuffer->handle); + // if front buffer still being tracked update slot state + if (stillTracking(front)) { + mSlots[buf].mAcquireCalled = true; + mSlots[buf].mNeedsCleanupOnRelease = false; + mSlots[buf].mBufferState = BufferSlot::ACQUIRED; + mSlots[buf].mFence = Fence::NO_FENCE; + } + + // If the buffer has previously been acquired by the consumer, set + // mGraphicBuffer to NULL to avoid unnecessarily remapping this + // buffer on the consumer side. + if (buffer->mAcquireCalled) { buffer->mGraphicBuffer = NULL; - } else { - buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; } - buffer->mCrop = mSlots[buf].mCrop; - buffer->mTransform = mSlots[buf].mTransform; - buffer->mScalingMode = mSlots[buf].mScalingMode; - buffer->mFrameNumber = mSlots[buf].mFrameNumber; - buffer->mTimestamp = mSlots[buf].mTimestamp; - buffer->mBuf = buf; - buffer->mFence = mSlots[buf].mFence; - - mSlots[buf].mAcquireCalled = true; - mSlots[buf].mNeedsCleanupOnRelease = false; - mSlots[buf].mBufferState = BufferSlot::ACQUIRED; - mSlots[buf].mFence = Fence::NO_FENCE; mQueue.erase(front); mDequeueCondition.broadcast(); @@ -862,7 +865,8 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) { return NO_ERROR; } -status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, +status_t BufferQueue::releaseBuffer( + int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR eglFence, const sp<Fence>& fence) { ATRACE_CALL(); ATRACE_BUFFER_INDEX(buf); @@ -873,12 +877,35 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, return BAD_VALUE; } - mSlots[buf].mEglDisplay = display; - mSlots[buf].mEglFence = eglFence; - mSlots[buf].mFence = fence; + // Check if this buffer slot is on the queue + bool slotQueued = false; + Fifo::iterator front(mQueue.begin()); + while (front != mQueue.end() && !slotQueued) { + if (front->mBuf == buf) + slotQueued = true; + front++; + } + + // If the frame number has changed because buffer has been reallocated, + // we can ignore this releaseBuffer for the old buffer. + if (frameNumber != mSlots[buf].mFrameNumber) { + // This should only occur if new buffer is still in the queue + ALOGE_IF(!slotQueued, + "received old buffer(#%lld) after new buffer(#%lld) on same " + "slot #%d already acquired", frameNumber, + mSlots[buf].mFrameNumber, buf); + return STALE_BUFFER_SLOT; + } + // this should never happen + ALOGE_IF(slotQueued, + "received new buffer(#%lld) on slot #%d that has not yet been " + "acquired", frameNumber, buf); // The buffer can now only be released if its in the acquired state if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { + mSlots[buf].mEglDisplay = display; + mSlots[buf].mEglFence = eglFence; + mSlots[buf].mFence = fence; mSlots[buf].mBufferState = BufferSlot::FREE; } else if (mSlots[buf].mNeedsCleanupOnRelease) { ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState); @@ -943,6 +970,17 @@ status_t BufferQueue::getReleasedBuffers(uint32_t* slotMask) { mask |= 1 << i; } } + + // Remove buffers in flight (on the queue) from the mask where acquire has + // been called, as the consumer will not receive the buffer address, so + // it should not free these slots. + Fifo::iterator front(mQueue.begin()); + while (front != mQueue.end()) { + if (front->mAcquireCalled) + mask &= ~(1 << front->mBuf); + front++; + } + *slotMask = mask; ST_LOGV("getReleasedBuffers: returning mask %#x", mask); @@ -985,20 +1023,6 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { return NO_ERROR; } -void BufferQueue::freeAllBuffersExceptHeadLocked() { - int head = -1; - if (!mQueue.empty()) { - Fifo::iterator front(mQueue.begin()); - head = *front; - } - mBufferHasBeenQueued = false; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (i != head) { - freeBufferLocked(i); - } - } -} - status_t BufferQueue::drainQueueLocked() { while (mSynchronousMode && mQueue.size() > 1) { mDequeueCondition.wait(mMutex); @@ -1017,11 +1041,7 @@ status_t BufferQueue::drainQueueLocked() { status_t BufferQueue::drainQueueAndFreeBuffersLocked() { status_t err = drainQueueLocked(); if (err == NO_ERROR) { - if (mQueue.empty()) { - freeAllBuffersLocked(); - } else { - freeAllBuffersExceptHeadLocked(); - } + freeAllBuffersLocked(); } return err; } @@ -1061,6 +1081,22 @@ int BufferQueue::getMaxBufferCountLocked() const { return maxBufferCount; } +bool BufferQueue::stillTracking(const BufferItem *item) const { + const BufferSlot &slot = mSlots[item->mBuf]; + + ST_LOGV("stillTracking?: item: { slot=%d/%llu, buffer=%p }, " + "slot: { slot=%d/%llu, buffer=%p }", + item->mBuf, item->mFrameNumber, + (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0), + item->mBuf, slot.mFrameNumber, + (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0)); + + // Compare item with its original buffer slot. We can check the slot + // as the buffer would not be moved to a different slot by the producer. + return (slot.mGraphicBuffer != NULL && + item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle); +} + BufferQueue::ProxyConsumerListener::ProxyConsumerListener( const wp<BufferQueue::ConsumerListener>& consumerListener): mConsumerListener(consumerListener) {} diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 4937b17..fd9d153 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -95,6 +95,7 @@ void ConsumerBase::freeBufferLocked(int slotIndex) { CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); mSlots[slotIndex].mGraphicBuffer = 0; mSlots[slotIndex].mFence = Fence::NO_FENCE; + mSlots[slotIndex].mFrameNumber = 0; } // Used for refactoring, should not be in final interface @@ -165,23 +166,19 @@ void ConsumerBase::setFrameAvailableListener( } void ConsumerBase::dump(String8& result) const { - char buffer[1024]; - dump(result, "", buffer, 1024); + dump(result, ""); } -void ConsumerBase::dump(String8& result, const char* prefix, - char* buffer, size_t size) const { +void ConsumerBase::dump(String8& result, const char* prefix) const { Mutex::Autolock _l(mMutex); - dumpLocked(result, prefix, buffer, size); + dumpLocked(result, prefix); } -void ConsumerBase::dumpLocked(String8& result, const char* prefix, - char* buffer, size_t SIZE) const { - snprintf(buffer, SIZE, "%smAbandoned=%d\n", prefix, int(mAbandoned)); - result.append(buffer); +void ConsumerBase::dumpLocked(String8& result, const char* prefix) const { + result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned)); if (!mAbandoned) { - mBufferQueue->dump(result, prefix, buffer, SIZE); + mBufferQueue->dump(result, prefix); } } @@ -195,21 +192,31 @@ status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) { mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; } + mSlots[item->mBuf].mFrameNumber = item->mFrameNumber; mSlots[item->mBuf].mFence = item->mFence; - CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf); + CB_LOGV("acquireBufferLocked: -> slot=%d/%llu", + item->mBuf, item->mFrameNumber); return OK; } -status_t ConsumerBase::addReleaseFence(int slot, const sp<Fence>& fence) { +status_t ConsumerBase::addReleaseFence(int slot, + const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { Mutex::Autolock lock(mMutex); - return addReleaseFenceLocked(slot, fence); + return addReleaseFenceLocked(slot, graphicBuffer, fence); } -status_t ConsumerBase::addReleaseFenceLocked(int slot, const sp<Fence>& fence) { +status_t ConsumerBase::addReleaseFenceLocked(int slot, + const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { CB_LOGV("addReleaseFenceLocked: slot=%d", slot); + // If consumer no longer tracks this graphicBuffer, we can safely + // drop this fence, as it will never be received by the producer. + if (!stillTracking(slot, graphicBuffer)) { + return OK; + } + if (!mSlots[slot].mFence.get()) { mSlots[slot].mFence = fence; } else { @@ -229,11 +236,20 @@ status_t ConsumerBase::addReleaseFenceLocked(int slot, const sp<Fence>& fence) { return OK; } -status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display, - EGLSyncKHR eglFence) { - CB_LOGV("releaseBufferLocked: slot=%d", slot); - status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence, - mSlots[slot].mFence); +status_t ConsumerBase::releaseBufferLocked( + int slot, const sp<GraphicBuffer> graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence) { + // If consumer no longer tracks this graphicBuffer (we received a new + // buffer on the same slot), the buffer producer is definitely no longer + // tracking it. + if (!stillTracking(slot, graphicBuffer)) { + return OK; + } + + CB_LOGV("releaseBufferLocked: slot=%d/%llu", + slot, mSlots[slot].mFrameNumber); + status_t err = mBufferQueue->releaseBuffer(slot, mSlots[slot].mFrameNumber, + display, eglFence, mSlots[slot].mFence); if (err == BufferQueue::STALE_BUFFER_SLOT) { freeBufferLocked(slot); } @@ -243,4 +259,13 @@ status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display, return err; } +bool ConsumerBase::stillTracking(int slot, + const sp<GraphicBuffer> graphicBuffer) { + if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) { + return false; + } + return (mSlots[slot].mGraphicBuffer != NULL && + mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); +} + } // namespace android diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index 0543649..123b470 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -55,6 +55,18 @@ void CpuConsumer::setName(const String8& name) { mBufferQueue->setConsumerName(name); } +status_t CpuConsumer::setDefaultBufferSize(uint32_t width, uint32_t height) +{ + Mutex::Autolock _l(mMutex); + return mBufferQueue->setDefaultBufferSize(width, height); +} + +status_t CpuConsumer::setDefaultBufferFormat(uint32_t defaultFormat) +{ + Mutex::Autolock _l(mMutex); + return mBufferQueue->setDefaultBufferFormat(defaultFormat); +} + status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t err; @@ -189,7 +201,9 @@ status_t CpuConsumer::releaseAcquiredBufferLocked(int lockedIdx) { // disconnected after this buffer was acquired. if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer == mSlots[buf].mGraphicBuffer)) { - releaseBufferLocked(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + releaseBufferLocked( + buf, mAcquiredBuffers[lockedIdx].mGraphicBuffer, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); } AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index bec0f90..6d29edc 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -188,12 +188,16 @@ status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item) { return NO_ERROR; } -status_t GLConsumer::releaseBufferLocked(int buf, EGLDisplay display, - EGLSyncKHR eglFence) { - status_t err = ConsumerBase::releaseBufferLocked(buf, display, eglFence); - +status_t GLConsumer::releaseBufferLocked(int buf, + sp<GraphicBuffer> graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence) { + // release the buffer if it hasn't already been discarded by the + // BufferQueue. This can happen, for example, when the producer of this + // buffer has reallocated the original buffer slot after this buffer + // was acquired. + status_t err = ConsumerBase::releaseBufferLocked( + buf, graphicBuffer, display, eglFence); mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR; - return err; } @@ -237,7 +241,10 @@ status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) if (err != NO_ERROR) { // Release the buffer we just acquired. It's not safe to // release the old buffer, so instead we just drop the new frame. - releaseBufferLocked(buf, mEglDisplay, EGL_NO_SYNC_KHR); + // As we are still under lock since acquireBuffer, it is safe to + // release by slot. + releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, + mEglDisplay, EGL_NO_SYNC_KHR); return err; } @@ -248,7 +255,8 @@ status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) // release old buffer if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - status_t status = releaseBufferLocked(mCurrentTexture, mEglDisplay, + status_t status = releaseBufferLocked( + mCurrentTexture, mCurrentTextureBuf, mEglDisplay, mEglSlots[mCurrentTexture].mEglFence); if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) { ST_LOGE("releaseAndUpdate: failed to release buffer: %s (%d)", @@ -334,7 +342,8 @@ status_t GLConsumer::checkAndUpdateEglStateLocked() { void GLConsumer::setReleaseFence(const sp<Fence>& fence) { if (fence->isValid() && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - status_t err = addReleaseFence(mCurrentTexture, fence); + status_t err = addReleaseFence(mCurrentTexture, + mCurrentTextureBuf, fence); if (err != OK) { ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); @@ -503,7 +512,8 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { return UNKNOWN_ERROR; } sp<Fence> fence(new Fence(fenceFd)); - status_t err = addReleaseFenceLocked(mCurrentTexture, fence); + status_t err = addReleaseFenceLocked(mCurrentTexture, + mCurrentTextureBuf, fence); if (err != OK) { ST_LOGE("syncForReleaseLocked: error adding release fence: " "%s (%d)", strerror(-err), err); @@ -887,18 +897,16 @@ status_t GLConsumer::setSynchronousMode(bool enabled) { return mBufferQueue->setSynchronousMode(enabled); } -void GLConsumer::dumpLocked(String8& result, const char* prefix, - char* buffer, size_t size) const +void GLConsumer::dumpLocked(String8& result, const char* prefix) const { - snprintf(buffer, size, + result.appendFormat( "%smTexName=%d mCurrentTexture=%d\n" "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n", prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, mCurrentTransform); - result.append(buffer); - ConsumerBase::dumpLocked(result, prefix, buffer, size); + ConsumerBase::dumpLocked(result, prefix); } static void mtxMul(float out[16], const float a[16], const float b[16]) { diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp index c4dd55b..b480f3a 100644 --- a/libs/ui/Rect.cpp +++ b/libs/ui/Rect.cpp @@ -20,11 +20,11 @@ namespace android { static inline int32_t min(int32_t a, int32_t b) { - return (a<b) ? a : b; + return (a < b) ? a : b; } static inline int32_t max(int32_t a, int32_t b) { - return (a>b) ? a : b; + return (a > b) ? a : b; } void Rect::makeInvalid() { @@ -34,18 +34,17 @@ void Rect::makeInvalid() { bottom = -1; } -bool Rect::operator < (const Rect& rhs) const -{ - if (top<rhs.top) { +bool Rect::operator <(const Rect& rhs) const { + if (top < rhs.top) { return true; } else if (top == rhs.top) { if (left < rhs.left) { return true; } else if (left == rhs.left) { - if (bottom<rhs.bottom) { + if (bottom < rhs.bottom) { return true; } else if (bottom == rhs.bottom) { - if (right<rhs.right) { + if (right < rhs.right) { return true; } } @@ -54,8 +53,7 @@ bool Rect::operator < (const Rect& rhs) const return false; } -Rect& Rect::offsetTo(int32_t x, int32_t y) -{ +Rect& Rect::offsetTo(int32_t x, int32_t y) { right -= left - x; bottom -= top - y; left = x; @@ -63,45 +61,41 @@ Rect& Rect::offsetTo(int32_t x, int32_t y) return *this; } -Rect& Rect::offsetBy(int32_t x, int32_t y) -{ +Rect& Rect::offsetBy(int32_t x, int32_t y) { left += x; - top += y; - right+= x; - bottom+=y; + top += y; + right += x; + bottom += y; return *this; } -const Rect Rect::operator + (const Point& rhs) const -{ - const Rect result(left+rhs.x, top+rhs.y, right+rhs.x, bottom+rhs.y); +const Rect Rect::operator +(const Point& rhs) const { + const Rect result(left + rhs.x, top + rhs.y, right + rhs.x, bottom + rhs.y); return result; } -const Rect Rect::operator - (const Point& rhs) const -{ - const Rect result(left-rhs.x, top-rhs.y, right-rhs.x, bottom-rhs.y); +const Rect Rect::operator -(const Point& rhs) const { + const Rect result(left - rhs.x, top - rhs.y, right - rhs.x, bottom - rhs.y); return result; } -bool Rect::intersect(const Rect& with, Rect* result) const -{ - result->left = max(left, with.left); - result->top = max(top, with.top); - result->right = min(right, with.right); - result->bottom = min(bottom, with.bottom); +bool Rect::intersect(const Rect& with, Rect* result) const { + result->left = max(left, with.left); + result->top = max(top, with.top); + result->right = min(right, with.right); + result->bottom = min(bottom, with.bottom); return !(result->isEmpty()); } Rect Rect::transform(uint32_t xform, int32_t width, int32_t height) const { Rect result(*this); if (xform & HAL_TRANSFORM_FLIP_H) { - result = Rect(width - result.right, result.top, - width - result.left, result.bottom); + result = Rect(width - result.right, result.top, width - result.left, + result.bottom); } if (xform & HAL_TRANSFORM_FLIP_V) { - result = Rect(result.left, height - result.bottom, - result.right, height - result.top); + result = Rect(result.left, height - result.bottom, result.right, + height - result.top); } if (xform & HAL_TRANSFORM_ROT_90) { int left = height - result.bottom; @@ -113,4 +107,35 @@ Rect Rect::transform(uint32_t xform, int32_t width, int32_t height) const { return result; } +Rect Rect::reduce(const Rect& exclude) const { + Rect result; + + uint32_t mask = 0; + mask |= (exclude.left > left) ? 1 : 0; + mask |= (exclude.top > top) ? 2 : 0; + mask |= (exclude.right < right) ? 4 : 0; + mask |= (exclude.bottom < bottom) ? 8 : 0; + + if (mask == 0) { + // crop entirely covers us + result.clear(); + } else { + result = *this; + if (!(mask & (mask - 1))) { + // power-of-2, i.e.: just one bit is set + if (mask & 1) { + result.right = exclude.left; + } else if (mask & 2) { + result.bottom = exclude.top; + } else if (mask & 4) { + result.left = exclude.right; + } else if (mask & 8) { + result.top = exclude.bottom; + } + } + } + + return result; +} + }; // namespace android diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index bf01488..623f8ed 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -697,7 +697,7 @@ void Region::translate(Region& reg, int dx, int dy) size_t count = reg.mStorage.size(); Rect* rects = reg.mStorage.editArray(); while (count) { - rects->translate(dx, dy); + rects->offsetBy(dx, dy); rects++; count--; } diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk index cbfe7bd..42e1c7e 100644 --- a/libs/utils/Android.mk +++ b/libs/utils/Android.mk @@ -20,9 +20,7 @@ LOCAL_PATH:= $(call my-dir) commonSources:= \ BasicHashtable.cpp \ BlobCache.cpp \ - BufferedTextOutput.cpp \ CallStack.cpp \ - Debug.cpp \ FileMap.cpp \ Flattenable.cpp \ JenkinsHash.cpp \ @@ -36,18 +34,12 @@ commonSources:= \ StopWatch.cpp \ String8.cpp \ String16.cpp \ - StringArray.cpp \ SystemClock.cpp \ - TextOutput.cpp \ Threads.cpp \ Timers.cpp \ Tokenizer.cpp \ Unicode.cpp \ VectorImpl.cpp \ - WorkQueue.cpp \ - ZipFileCRO.cpp \ - ZipFileRO.cpp \ - ZipUtils.cpp \ misc.cpp host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) @@ -74,9 +66,6 @@ ifeq ($(HOST_OS), linux) LOCAL_SRC_FILES += Looper.cpp endif LOCAL_MODULE:= libutils -LOCAL_STATIC_LIBRARIES := libz -LOCAL_C_INCLUDES := \ - external/zlib LOCAL_CFLAGS += $(host_commonCflags) LOCAL_LDLIBS += $(host_commonLdlibs) include $(BUILD_HOST_STATIC_LIBRARY) @@ -90,15 +79,12 @@ ifeq ($(HOST_OS), linux) LOCAL_SRC_FILES += Looper.cpp endif LOCAL_MODULE:= lib64utils -LOCAL_STATIC_LIBRARIES := libz -LOCAL_C_INCLUDES := \ - external/zlib LOCAL_CFLAGS += $(host_commonCflags) -m64 LOCAL_LDLIBS += $(host_commonLdlibs) include $(BUILD_HOST_STATIC_LIBRARY) -# For the device +# For the device, static # ===================================================== include $(CLEAR_VARS) @@ -123,14 +109,28 @@ LOCAL_C_INCLUDES += \ LOCAL_LDLIBS += -lpthread +LOCAL_STATIC_LIBRARIES := \ + libcutils + LOCAL_SHARED_LIBRARIES := \ - liblog \ - libcutils \ - libdl \ - libcorkscrew \ - libz + libcorkscrew \ + liblog \ + libdl LOCAL_MODULE:= libutils +include $(BUILD_STATIC_LIBRARY) + +# For the device, shared +# ===================================================== +include $(CLEAR_VARS) +LOCAL_MODULE:= libutils +LOCAL_WHOLE_STATIC_LIBRARIES := libutils +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libdl \ + libcorkscrew + include $(BUILD_SHARED_LIBRARY) # Include subdirectory makefiles diff --git a/libs/utils/Looper.cpp b/libs/utils/Looper.cpp index a5e6645..c51df2d 100644 --- a/libs/utils/Looper.cpp +++ b/libs/utils/Looper.cpp @@ -84,6 +84,8 @@ Looper::Looper(bool allowNonCallbacks) : LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", errno); + mIdling = false; + // Allocate the epoll instance and register the wake pipe. mEpollFd = epoll_create(EPOLL_SIZE_HINT); LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); @@ -214,9 +216,15 @@ int Looper::pollInner(int timeoutMillis) { mResponses.clear(); mResponseIndex = 0; + // We are about to idle. + mIdling = true; + struct epoll_event eventItems[EPOLL_MAX_EVENTS]; int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); + // No longer idling. + mIdling = false; + // Acquire lock. mLock.lock(); @@ -558,4 +566,8 @@ void Looper::removeMessages(const sp<MessageHandler>& handler, int what) { } // release lock } +bool Looper::isIdling() const { + return mIdling; +} + } // namespace android diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp index e538f68..f398a82 100644 --- a/libs/utils/RefBase.cpp +++ b/libs/utils/RefBase.cpp @@ -23,7 +23,6 @@ #include <utils/CallStack.h> #include <utils/Log.h> #include <utils/threads.h> -#include <utils/TextOutput.h> #include <stdlib.h> #include <stdio.h> @@ -648,19 +647,4 @@ void RefBase::renameRefId(RefBase* ref, ref->mRefs->renameWeakRefId(old_id, new_id); } -// --------------------------------------------------------------------------- - -TextOutput& printStrongPointer(TextOutput& to, const void* val) -{ - to << "sp<>(" << val << ")"; - return to; -} - -TextOutput& printWeakPointer(TextOutput& to, const void* val) -{ - to << "wp<>(" << val << ")"; - return to; -} - - }; // namespace android diff --git a/libs/utils/Static.cpp b/libs/utils/Static.cpp index 624e917..3ed07a1 100644 --- a/libs/utils/Static.cpp +++ b/libs/utils/Static.cpp @@ -17,12 +17,15 @@ // All static variables go here, to control initialization and // destruction order in the library. -#include <private/utils/Static.h> +namespace android { -#include <utils/BufferedTextOutput.h> -#include <utils/Log.h> +// For String8.cpp +extern void initialize_string8(); +extern void terminate_string8(); -namespace android { +// For String16.cpp +extern void initialize_string16(); +extern void terminate_string16(); class LibUtilsFirstStatics { @@ -43,49 +46,4 @@ public: static LibUtilsFirstStatics gFirstStatics; int gDarwinCantLoadAllObjects = 1; -// ------------ Text output streams - -Vector<int32_t> gTextBuffers; - -class LogTextOutput : public BufferedTextOutput -{ -public: - LogTextOutput() : BufferedTextOutput(MULTITHREADED) { } - virtual ~LogTextOutput() { }; - -protected: - virtual status_t writeLines(const struct iovec& vec, size_t N) - { - //android_writevLog(&vec, N); <-- this is now a no-op - if (N != 1) ALOGI("WARNING: writeLines N=%zu\n", N); - ALOGI("%.*s", (int)vec.iov_len, (const char*) vec.iov_base); - return NO_ERROR; - } -}; - -class FdTextOutput : public BufferedTextOutput -{ -public: - FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { } - virtual ~FdTextOutput() { }; - -protected: - virtual status_t writeLines(const struct iovec& vec, size_t N) - { - writev(mFD, &vec, N); - return NO_ERROR; - } - -private: - int mFD; -}; - -static LogTextOutput gLogTextOutput; -static FdTextOutput gStdoutTextOutput(STDOUT_FILENO); -static FdTextOutput gStderrTextOutput(STDERR_FILENO); - -TextOutput& alog(gLogTextOutput); -TextOutput& aout(gStdoutTextOutput); -TextOutput& aerr(gStderrTextOutput); - } // namespace android diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp index 94e072f..b09b728 100644 --- a/libs/utils/String16.cpp +++ b/libs/utils/String16.cpp @@ -20,11 +20,8 @@ #include <utils/Log.h> #include <utils/Unicode.h> #include <utils/String8.h> -#include <utils/TextOutput.h> #include <utils/threads.h> -#include <private/utils/Static.h> - #include <memory.h> #include <stdio.h> #include <ctype.h> @@ -96,6 +93,19 @@ String16::String16() { } +String16::String16(StaticLinkage) + : mString(0) +{ + // this constructor is used when we can't rely on the static-initializers + // having run. In this case we always allocate an empty string. It's less + // efficient than using getEmptyString(), but we assume it's uncommon. + + char16_t* data = static_cast<char16_t*>( + SharedBuffer::alloc(sizeof(char16_t))->data()); + data[0] = 0; + mString = data; +} + String16::String16(const String16& o) : mString(o.mString) { @@ -409,10 +419,4 @@ status_t String16::remove(size_t len, size_t begin) return NO_MEMORY; } -TextOutput& operator<<(TextOutput& to, const String16& val) -{ - to << String8(val).string(); - return to; -} - }; // namespace android diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp index 562f026..e852d77 100644 --- a/libs/utils/String8.cpp +++ b/libs/utils/String8.cpp @@ -20,11 +20,8 @@ #include <utils/Unicode.h> #include <utils/SharedBuffer.h> #include <utils/String16.h> -#include <utils/TextOutput.h> #include <utils/threads.h> -#include <private/utils/Static.h> - #include <ctype.h> /* @@ -46,6 +43,8 @@ static char* gEmptyString = NULL; extern int gDarwinCantLoadAllObjects; int gDarwinIsReallyAnnoying; +void initialize_string8(); + static inline char* getEmptyString() { gEmptyStringBuf->acquire(); @@ -143,6 +142,19 @@ String8::String8() { } +String8::String8(StaticLinkage) + : mString(0) +{ + // this constructor is used when we can't rely on the static-initializers + // having run. In this case we always allocate an empty string. It's less + // efficient than using getEmptyString(), but we assume it's uncommon. + + char* data = static_cast<char*>( + SharedBuffer::alloc(sizeof(char))->data()); + data[0] = 0; + mString = data; +} + String8::String8(const String8& o) : mString(o.mString) { @@ -450,12 +462,6 @@ void String8::getUtf32(char32_t* dst) const utf8_to_utf32(mString, length(), dst); } -TextOutput& operator<<(TextOutput& to, const String8& val) -{ - to << val.string(); - return to; -} - // --------------------------------------------------------------------------- // Path functions diff --git a/libs/utils/StringArray.cpp b/libs/utils/StringArray.cpp deleted file mode 100644 index aa42d68..0000000 --- a/libs/utils/StringArray.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -// -// Sortable array of strings. STL-ish, but STL-free. -// - -#include <stdlib.h> -#include <string.h> - -#include <utils/StringArray.h> - -namespace android { - -// -// An expanding array of strings. Add, get, sort, delete. -// -StringArray::StringArray() - : mMax(0), mCurrent(0), mArray(NULL) -{ -} - -StringArray:: ~StringArray() { - for (int i = 0; i < mCurrent; i++) - delete[] mArray[i]; - delete[] mArray; -} - -// -// Add a string. A copy of the string is made. -// -bool StringArray::push_back(const char* str) { - if (mCurrent >= mMax) { - char** tmp; - - if (mMax == 0) - mMax = 16; // initial storage - else - mMax *= 2; - - tmp = new char*[mMax]; - if (tmp == NULL) - return false; - - memcpy(tmp, mArray, mCurrent * sizeof(char*)); - delete[] mArray; - mArray = tmp; - } - - int len = strlen(str); - mArray[mCurrent] = new char[len+1]; - memcpy(mArray[mCurrent], str, len+1); - mCurrent++; - - return true; -} - -// -// Delete an entry. -// -void StringArray::erase(int idx) { - if (idx < 0 || idx >= mCurrent) - return; - delete[] mArray[idx]; - if (idx < mCurrent-1) { - memmove(&mArray[idx], &mArray[idx+1], - (mCurrent-1 - idx) * sizeof(char*)); - } - mCurrent--; -} - -// -// Sort the array. -// -void StringArray::sort(int (*compare)(const void*, const void*)) { - qsort(mArray, mCurrent, sizeof(char*), compare); -} - -// -// Pass this to the sort routine to do an ascending alphabetical sort. -// -int StringArray::cmpAscendingAlpha(const void* pstr1, const void* pstr2) { - return strcmp(*(const char**)pstr1, *(const char**)pstr2); -} - -// -// Set entry N to specified string. -// [should use operator[] here] -// -void StringArray::setEntry(int idx, const char* str) { - if (idx < 0 || idx >= mCurrent) - return; - delete[] mArray[idx]; - int len = strlen(str); - mArray[idx] = new char[len+1]; - memcpy(mArray[idx], str, len+1); -} - - -}; // namespace android diff --git a/libs/utils/SystemClock.cpp b/libs/utils/SystemClock.cpp index ec2d82e..4b74889 100644 --- a/libs/utils/SystemClock.cpp +++ b/libs/utils/SystemClock.cpp @@ -36,63 +36,11 @@ #include <utils/Timers.h> #define LOG_TAG "SystemClock" -#include "utils/Log.h" +#include <utils/Log.h> namespace android { /* - * Set the current time. This only works when running as root. - */ -int setCurrentTimeMillis(int64_t millis) -{ -#if WIN32 - // not implemented - return -1; -#else - struct timeval tv; -#ifdef HAVE_ANDROID_OS - struct timespec ts; - int fd; - int res; -#endif - int ret = 0; - - if (millis <= 0 || millis / 1000LL >= INT_MAX) { - return -1; - } - - tv.tv_sec = (time_t) (millis / 1000LL); - tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL); - - ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec); - -#ifdef HAVE_ANDROID_OS - fd = open("/dev/alarm", O_RDWR); - if(fd < 0) { - ALOGW("Unable to open alarm driver: %s\n", strerror(errno)); - return -1; - } - ts.tv_sec = tv.tv_sec; - ts.tv_nsec = tv.tv_usec * 1000; - res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts); - if(res < 0) { - ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno)); - ret = -1; - } - close(fd); -#else - if (settimeofday(&tv, NULL) != 0) { - ALOGW("Unable to set clock to %d.%d: %s\n", - (int) tv.tv_sec, (int) tv.tv_usec, strerror(errno)); - ret = -1; - } -#endif - - return ret; -#endif // WIN32 -} - -/* * native public static long uptimeMillis(); */ int64_t uptimeMillis() diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp index 7b877e0..ff74914 100644 --- a/libs/utils/Threads.cpp +++ b/libs/utils/Threads.cpp @@ -21,7 +21,6 @@ #include <utils/Log.h> #include <cutils/sched_policy.h> -#include <cutils/properties.h> #include <stdio.h> #include <stdlib.h> @@ -68,20 +67,6 @@ using namespace android; typedef void* (*android_pthread_entry)(void*); -static pthread_once_t gDoSchedulingGroupOnce = PTHREAD_ONCE_INIT; -static bool gDoSchedulingGroup = true; - -static void checkDoSchedulingGroup(void) { - char buf[PROPERTY_VALUE_MAX]; - int len = property_get("debug.sys.noschedgroups", buf, ""); - if (len > 0) { - int temp; - if (sscanf(buf, "%d", &temp) == 1) { - gDoSchedulingGroup = temp == 0; - } - } -} - struct thread_data_t { thread_func_t entryFunction; void* userData; @@ -97,15 +82,10 @@ struct thread_data_t { char * name = t->threadName; delete t; setpriority(PRIO_PROCESS, 0, prio); - pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup); - if (gDoSchedulingGroup) { - if (prio >= ANDROID_PRIORITY_BACKGROUND) { - set_sched_policy(androidGetTid(), SP_BACKGROUND); - } else if (prio > ANDROID_PRIORITY_AUDIO) { - set_sched_policy(androidGetTid(), SP_FOREGROUND); - } else { - // defaults to that of parent, or as set by requestPriority() - } + if (prio >= ANDROID_PRIORITY_BACKGROUND) { + set_sched_policy(0, SP_BACKGROUND); + } else { + set_sched_policy(0, SP_FOREGROUND); } if (name) { @@ -337,20 +317,10 @@ int androidSetThreadPriority(pid_t tid, int pri) #if defined(HAVE_PTHREADS) int lasterr = 0; - pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup); - if (gDoSchedulingGroup) { - // set_sched_policy does not support tid == 0 - int policy_tid; - if (tid == 0) { - policy_tid = androidGetTid(); - } else { - policy_tid = tid; - } - if (pri >= ANDROID_PRIORITY_BACKGROUND) { - rc = set_sched_policy(policy_tid, SP_BACKGROUND); - } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) { - rc = set_sched_policy(policy_tid, SP_FOREGROUND); - } + if (pri >= ANDROID_PRIORITY_BACKGROUND) { + rc = set_sched_policy(tid, SP_BACKGROUND); + } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) { + rc = set_sched_policy(tid, SP_FOREGROUND); } if (rc) { diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp index d4f8516..5293cd2 100644 --- a/libs/utils/Timers.cpp +++ b/libs/utils/Timers.cpp @@ -70,65 +70,3 @@ int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) } return timeoutDelayMillis; } - - -/* - * =========================================================================== - * DurationTimer - * =========================================================================== - */ - -using namespace android; - -// Start the timer. -void DurationTimer::start(void) -{ - gettimeofday(&mStartWhen, NULL); -} - -// Stop the timer. -void DurationTimer::stop(void) -{ - gettimeofday(&mStopWhen, NULL); -} - -// Get the duration in microseconds. -long long DurationTimer::durationUsecs(void) const -{ - return (long) subtractTimevals(&mStopWhen, &mStartWhen); -} - -// Subtract two timevals. Returns the difference (ptv1-ptv2) in -// microseconds. -/*static*/ long long DurationTimer::subtractTimevals(const struct timeval* ptv1, - const struct timeval* ptv2) -{ - long long stop = ((long long) ptv1->tv_sec) * 1000000LL + - ((long long) ptv1->tv_usec); - long long start = ((long long) ptv2->tv_sec) * 1000000LL + - ((long long) ptv2->tv_usec); - return stop - start; -} - -// Add the specified amount of time to the timeval. -/*static*/ void DurationTimer::addToTimeval(struct timeval* ptv, long usec) -{ - if (usec < 0) { - ALOG(LOG_WARN, "", "Negative values not supported in addToTimeval\n"); - return; - } - - // normalize tv_usec if necessary - if (ptv->tv_usec >= 1000000) { - ptv->tv_sec += ptv->tv_usec / 1000000; - ptv->tv_usec %= 1000000; - } - - ptv->tv_usec += usec % 1000000; - if (ptv->tv_usec >= 1000000) { - ptv->tv_usec -= 1000000; - ptv->tv_sec++; - } - ptv->tv_sec += usec / 1000000; -} - diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp index 70f49de..5a79647 100644 --- a/libs/utils/VectorImpl.cpp +++ b/libs/utils/VectorImpl.cpp @@ -504,15 +504,6 @@ void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) con do_move_backward(dest, from, num); } -void VectorImpl::reservedVectorImpl1() { } -void VectorImpl::reservedVectorImpl2() { } -void VectorImpl::reservedVectorImpl3() { } -void VectorImpl::reservedVectorImpl4() { } -void VectorImpl::reservedVectorImpl5() { } -void VectorImpl::reservedVectorImpl6() { } -void VectorImpl::reservedVectorImpl7() { } -void VectorImpl::reservedVectorImpl8() { } - /*****************************************************************************/ SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags) @@ -628,16 +619,6 @@ ssize_t SortedVectorImpl::remove(const void* item) return i; } -void SortedVectorImpl::reservedSortedVectorImpl1() { }; -void SortedVectorImpl::reservedSortedVectorImpl2() { }; -void SortedVectorImpl::reservedSortedVectorImpl3() { }; -void SortedVectorImpl::reservedSortedVectorImpl4() { }; -void SortedVectorImpl::reservedSortedVectorImpl5() { }; -void SortedVectorImpl::reservedSortedVectorImpl6() { }; -void SortedVectorImpl::reservedSortedVectorImpl7() { }; -void SortedVectorImpl::reservedSortedVectorImpl8() { }; - - /*****************************************************************************/ }; // namespace android diff --git a/libs/utils/WorkQueue.cpp b/libs/utils/WorkQueue.cpp deleted file mode 100644 index 3bb99a1..0000000 --- a/libs/utils/WorkQueue.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2012 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. - */ - -// #define LOG_NDEBUG 0 -#define LOG_TAG "WorkQueue" - -#include <utils/Log.h> -#include <utils/WorkQueue.h> - -namespace android { - -// --- WorkQueue --- - -WorkQueue::WorkQueue(size_t maxThreads, bool canCallJava) : - mMaxThreads(maxThreads), mCanCallJava(canCallJava), - mCanceled(false), mFinished(false), mIdleThreads(0) { -} - -WorkQueue::~WorkQueue() { - if (!cancel()) { - finish(); - } -} - -status_t WorkQueue::schedule(WorkUnit* workUnit, size_t backlog) { - AutoMutex _l(mLock); - - if (mFinished || mCanceled) { - return INVALID_OPERATION; - } - - if (mWorkThreads.size() < mMaxThreads - && mIdleThreads < mWorkUnits.size() + 1) { - sp<WorkThread> workThread = new WorkThread(this, mCanCallJava); - status_t status = workThread->run("WorkQueue::WorkThread"); - if (status) { - return status; - } - mWorkThreads.add(workThread); - mIdleThreads += 1; - } else if (backlog) { - while (mWorkUnits.size() >= mMaxThreads * backlog) { - mWorkDequeuedCondition.wait(mLock); - if (mFinished || mCanceled) { - return INVALID_OPERATION; - } - } - } - - mWorkUnits.add(workUnit); - mWorkChangedCondition.broadcast(); - return OK; -} - -status_t WorkQueue::cancel() { - AutoMutex _l(mLock); - - return cancelLocked(); -} - -status_t WorkQueue::cancelLocked() { - if (mFinished) { - return INVALID_OPERATION; - } - - if (!mCanceled) { - mCanceled = true; - - size_t count = mWorkUnits.size(); - for (size_t i = 0; i < count; i++) { - delete mWorkUnits.itemAt(i); - } - mWorkUnits.clear(); - mWorkChangedCondition.broadcast(); - mWorkDequeuedCondition.broadcast(); - } - return OK; -} - -status_t WorkQueue::finish() { - { // acquire lock - AutoMutex _l(mLock); - - if (mFinished) { - return INVALID_OPERATION; - } - - mFinished = true; - mWorkChangedCondition.broadcast(); - } // release lock - - // It is not possible for the list of work threads to change once the mFinished - // flag has been set, so we can access mWorkThreads outside of the lock here. - size_t count = mWorkThreads.size(); - for (size_t i = 0; i < count; i++) { - mWorkThreads.itemAt(i)->join(); - } - mWorkThreads.clear(); - return OK; -} - -bool WorkQueue::threadLoop() { - WorkUnit* workUnit; - { // acquire lock - AutoMutex _l(mLock); - - for (;;) { - if (mCanceled) { - return false; - } - - if (!mWorkUnits.isEmpty()) { - workUnit = mWorkUnits.itemAt(0); - mWorkUnits.removeAt(0); - mIdleThreads -= 1; - mWorkDequeuedCondition.broadcast(); - break; - } - - if (mFinished) { - return false; - } - - mWorkChangedCondition.wait(mLock); - } - } // release lock - - bool shouldContinue = workUnit->run(); - delete workUnit; - - { // acquire lock - AutoMutex _l(mLock); - - mIdleThreads += 1; - - if (!shouldContinue) { - cancelLocked(); - return false; - } - } // release lock - - return true; -} - -// --- WorkQueue::WorkThread --- - -WorkQueue::WorkThread::WorkThread(WorkQueue* workQueue, bool canCallJava) : - Thread(canCallJava), mWorkQueue(workQueue) { -} - -WorkQueue::WorkThread::~WorkThread() { -} - -bool WorkQueue::WorkThread::threadLoop() { - return mWorkQueue->threadLoop(); -} - -}; // namespace android diff --git a/libs/utils/ZipFileCRO.cpp b/libs/utils/ZipFileCRO.cpp deleted file mode 100644 index 55dfd9f..0000000 --- a/libs/utils/ZipFileCRO.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <utils/ZipFileCRO.h> -#include <utils/ZipFileRO.h> - -using namespace android; - -ZipFileCRO ZipFileXRO_open(const char* path) { - ZipFileRO* zip = new ZipFileRO(); - if (zip->open(path) == NO_ERROR) { - return (ZipFileCRO)zip; - } - return NULL; -} - -void ZipFileCRO_destroy(ZipFileCRO zipToken) { - ZipFileRO* zip = (ZipFileRO*)zipToken; - delete zip; -} - -ZipEntryCRO ZipFileCRO_findEntryByName(ZipFileCRO zipToken, - const char* fileName) { - ZipFileRO* zip = (ZipFileRO*)zipToken; - return (ZipEntryCRO)zip->findEntryByName(fileName); -} - -bool ZipFileCRO_getEntryInfo(ZipFileCRO zipToken, ZipEntryRO entryToken, - int* pMethod, size_t* pUncompLen, - size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) { - ZipFileRO* zip = (ZipFileRO*)zipToken; - ZipEntryRO entry = (ZipEntryRO)entryToken; - return zip->getEntryInfo(entry, pMethod, pUncompLen, pCompLen, pOffset, - pModWhen, pCrc32); -} - -bool ZipFileCRO_uncompressEntry(ZipFileCRO zipToken, ZipEntryRO entryToken, int fd) { - ZipFileRO* zip = (ZipFileRO*)zipToken; - ZipEntryRO entry = (ZipEntryRO)entryToken; - return zip->uncompressEntry(entry, fd); -} diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp deleted file mode 100644 index a1bfedb..0000000 --- a/libs/utils/ZipFileRO.cpp +++ /dev/null @@ -1,931 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -// -// Read-only access to Zip archives, with minimal heap allocation. -// -#define LOG_TAG "zipro" -//#define LOG_NDEBUG 0 -#include <utils/Log.h> -#include <utils/Compat.h> -#include <utils/ZipFileRO.h> -#include <utils/misc.h> -#include <utils/threads.h> - -#include <zlib.h> - -#include <string.h> -#include <fcntl.h> -#include <errno.h> -#include <assert.h> -#include <unistd.h> - -/* - * We must open binary files using open(path, ... | O_BINARY) under Windows. - * Otherwise strange read errors will happen. - */ -#ifndef O_BINARY -# define O_BINARY 0 -#endif - -using namespace android; - -/* - * Zip file constants. - */ -#define kEOCDSignature 0x06054b50 -#define kEOCDLen 22 -#define kEOCDNumEntries 8 // offset to #of entries in file -#define kEOCDSize 12 // size of the central directory -#define kEOCDFileOffset 16 // offset to central directory - -#define kMaxCommentLen 65535 // longest possible in ushort -#define kMaxEOCDSearch (kMaxCommentLen + kEOCDLen) - -#define kLFHSignature 0x04034b50 -#define kLFHLen 30 // excluding variable-len fields -#define kLFHNameLen 26 // offset to filename length -#define kLFHExtraLen 28 // offset to extra length - -#define kCDESignature 0x02014b50 -#define kCDELen 46 // excluding variable-len fields -#define kCDEMethod 10 // offset to compression method -#define kCDEModWhen 12 // offset to modification timestamp -#define kCDECRC 16 // offset to entry CRC -#define kCDECompLen 20 // offset to compressed length -#define kCDEUncompLen 24 // offset to uncompressed length -#define kCDENameLen 28 // offset to filename length -#define kCDEExtraLen 30 // offset to extra length -#define kCDECommentLen 32 // offset to comment length -#define kCDELocalOffset 42 // offset to local hdr - -/* - * The values we return for ZipEntryRO use 0 as an invalid value, so we - * want to adjust the hash table index by a fixed amount. Using a large - * value helps insure that people don't mix & match arguments, e.g. to - * findEntryByIndex(). - */ -#define kZipEntryAdj 10000 - -ZipFileRO::~ZipFileRO() { - free(mHashTable); - if (mDirectoryMap) - mDirectoryMap->release(); - if (mFd >= 0) - TEMP_FAILURE_RETRY(close(mFd)); - if (mFileName) - free(mFileName); -} - -/* - * Convert a ZipEntryRO to a hash table index, verifying that it's in a - * valid range. - */ -int ZipFileRO::entryToIndex(const ZipEntryRO entry) const -{ - long ent = ((intptr_t) entry) - kZipEntryAdj; - if (ent < 0 || ent >= mHashTableSize || mHashTable[ent].name == NULL) { - ALOGW("Invalid ZipEntryRO %p (%ld)\n", entry, ent); - return -1; - } - return ent; -} - - -/* - * Open the specified file read-only. We memory-map the entire thing and - * close the file before returning. - */ -status_t ZipFileRO::open(const char* zipFileName) -{ - int fd = -1; - - assert(mDirectoryMap == NULL); - - /* - * Open and map the specified file. - */ - fd = TEMP_FAILURE_RETRY(::open(zipFileName, O_RDONLY | O_BINARY)); - if (fd < 0) { - ALOGW("Unable to open zip '%s': %s\n", zipFileName, strerror(errno)); - return NAME_NOT_FOUND; - } - - mFileLength = lseek64(fd, 0, SEEK_END); - if (mFileLength < kEOCDLen) { - TEMP_FAILURE_RETRY(close(fd)); - return UNKNOWN_ERROR; - } - - if (mFileName != NULL) { - free(mFileName); - } - mFileName = strdup(zipFileName); - - mFd = fd; - - /* - * Find the Central Directory and store its size and number of entries. - */ - if (!mapCentralDirectory()) { - goto bail; - } - - /* - * Verify Central Directory and create data structures for fast access. - */ - if (!parseZipArchive()) { - goto bail; - } - - return OK; - -bail: - free(mFileName); - mFileName = NULL; - TEMP_FAILURE_RETRY(close(fd)); - return UNKNOWN_ERROR; -} - -/* - * Parse the Zip archive, verifying its contents and initializing internal - * data structures. - */ -bool ZipFileRO::mapCentralDirectory(void) -{ - ssize_t readAmount = kMaxEOCDSearch; - if (readAmount > (ssize_t) mFileLength) - readAmount = mFileLength; - - unsigned char* scanBuf = (unsigned char*) malloc(readAmount); - if (scanBuf == NULL) { - ALOGW("couldn't allocate scanBuf: %s", strerror(errno)); - free(scanBuf); - return false; - } - - /* - * Make sure this is a Zip archive. - */ - if (lseek64(mFd, 0, SEEK_SET) != 0) { - ALOGW("seek to start failed: %s", strerror(errno)); - free(scanBuf); - return false; - } - - ssize_t actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, sizeof(int32_t))); - if (actual != (ssize_t) sizeof(int32_t)) { - ALOGI("couldn't read first signature from zip archive: %s", strerror(errno)); - free(scanBuf); - return false; - } - - { - unsigned int header = get4LE(scanBuf); - if (header == kEOCDSignature) { - ALOGI("Found Zip archive, but it looks empty\n"); - free(scanBuf); - return false; - } else if (header != kLFHSignature) { - ALOGV("Not a Zip archive (found 0x%08x)\n", header); - free(scanBuf); - return false; - } - } - - /* - * Perform the traditional EOCD snipe hunt. - * - * We're searching for the End of Central Directory magic number, - * which appears at the start of the EOCD block. It's followed by - * 18 bytes of EOCD stuff and up to 64KB of archive comment. We - * need to read the last part of the file into a buffer, dig through - * it to find the magic number, parse some values out, and use those - * to determine the extent of the CD. - * - * We start by pulling in the last part of the file. - */ - off64_t searchStart = mFileLength - readAmount; - - if (lseek64(mFd, searchStart, SEEK_SET) != searchStart) { - ALOGW("seek %ld failed: %s\n", (long) searchStart, strerror(errno)); - free(scanBuf); - return false; - } - actual = TEMP_FAILURE_RETRY(read(mFd, scanBuf, readAmount)); - if (actual != (ssize_t) readAmount) { - ALOGW("Zip: read " ZD ", expected " ZD ". Failed: %s\n", - (ZD_TYPE) actual, (ZD_TYPE) readAmount, strerror(errno)); - free(scanBuf); - return false; - } - - /* - * Scan backward for the EOCD magic. In an archive without a trailing - * comment, we'll find it on the first try. (We may want to consider - * doing an initial minimal read; if we don't find it, retry with a - * second read as above.) - */ - int i; - for (i = readAmount - kEOCDLen; i >= 0; i--) { - if (scanBuf[i] == 0x50 && get4LE(&scanBuf[i]) == kEOCDSignature) { - ALOGV("+++ Found EOCD at buf+%d\n", i); - break; - } - } - if (i < 0) { - ALOGD("Zip: EOCD not found, %s is not zip\n", mFileName); - free(scanBuf); - return false; - } - - off64_t eocdOffset = searchStart + i; - const unsigned char* eocdPtr = scanBuf + i; - - assert(eocdOffset < mFileLength); - - /* - * Grab the CD offset and size, and the number of entries in the - * archive. After that, we can release our EOCD hunt buffer. - */ - unsigned int numEntries = get2LE(eocdPtr + kEOCDNumEntries); - unsigned int dirSize = get4LE(eocdPtr + kEOCDSize); - unsigned int dirOffset = get4LE(eocdPtr + kEOCDFileOffset); - free(scanBuf); - - // Verify that they look reasonable. - if ((long long) dirOffset + (long long) dirSize > (long long) eocdOffset) { - ALOGW("bad offsets (dir %ld, size %u, eocd %ld)\n", - (long) dirOffset, dirSize, (long) eocdOffset); - return false; - } - if (numEntries == 0) { - ALOGW("empty archive?\n"); - return false; - } - - ALOGV("+++ numEntries=%d dirSize=%d dirOffset=%d\n", - numEntries, dirSize, dirOffset); - - mDirectoryMap = new FileMap(); - if (mDirectoryMap == NULL) { - ALOGW("Unable to create directory map: %s", strerror(errno)); - return false; - } - - if (!mDirectoryMap->create(mFileName, mFd, dirOffset, dirSize, true)) { - ALOGW("Unable to map '%s' (" ZD " to " ZD "): %s\n", mFileName, - (ZD_TYPE) dirOffset, (ZD_TYPE) (dirOffset + dirSize), strerror(errno)); - return false; - } - - mNumEntries = numEntries; - mDirectoryOffset = dirOffset; - - return true; -} - - -/* - * Round up to the next highest power of 2. - * - * Found on http://graphics.stanford.edu/~seander/bithacks.html. - */ -static unsigned int roundUpPower2(unsigned int val) -{ - val--; - val |= val >> 1; - val |= val >> 2; - val |= val >> 4; - val |= val >> 8; - val |= val >> 16; - val++; - - return val; -} - -bool ZipFileRO::parseZipArchive(void) -{ - bool result = false; - const unsigned char* cdPtr = (const unsigned char*) mDirectoryMap->getDataPtr(); - size_t cdLength = mDirectoryMap->getDataLength(); - int numEntries = mNumEntries; - - /* - * Create hash table. We have a minimum 75% load factor, possibly as - * low as 50% after we round off to a power of 2. - */ - mHashTableSize = roundUpPower2(1 + (numEntries * 4) / 3); - mHashTable = (HashEntry*) calloc(mHashTableSize, sizeof(HashEntry)); - - /* - * Walk through the central directory, adding entries to the hash - * table. - */ - const unsigned char* ptr = cdPtr; - for (int i = 0; i < numEntries; i++) { - if (get4LE(ptr) != kCDESignature) { - ALOGW("Missed a central dir sig (at %d)\n", i); - goto bail; - } - if (ptr + kCDELen > cdPtr + cdLength) { - ALOGW("Ran off the end (at %d)\n", i); - goto bail; - } - - long localHdrOffset = (long) get4LE(ptr + kCDELocalOffset); - if (localHdrOffset >= mDirectoryOffset) { - ALOGW("bad LFH offset %ld at entry %d\n", localHdrOffset, i); - goto bail; - } - - unsigned int fileNameLen, extraLen, commentLen, hash; - - fileNameLen = get2LE(ptr + kCDENameLen); - extraLen = get2LE(ptr + kCDEExtraLen); - commentLen = get2LE(ptr + kCDECommentLen); - - /* add the CDE filename to the hash table */ - hash = computeHash((const char*)ptr + kCDELen, fileNameLen); - addToHash((const char*)ptr + kCDELen, fileNameLen, hash); - - ptr += kCDELen + fileNameLen + extraLen + commentLen; - if ((size_t)(ptr - cdPtr) > cdLength) { - ALOGW("bad CD advance (%d vs " ZD ") at entry %d\n", - (int) (ptr - cdPtr), (ZD_TYPE) cdLength, i); - goto bail; - } - } - ALOGV("+++ zip good scan %d entries\n", numEntries); - result = true; - -bail: - return result; -} - -/* - * Simple string hash function for non-null-terminated strings. - */ -/*static*/ unsigned int ZipFileRO::computeHash(const char* str, int len) -{ - unsigned int hash = 0; - - while (len--) - hash = hash * 31 + *str++; - - return hash; -} - -/* - * Add a new entry to the hash table. - */ -void ZipFileRO::addToHash(const char* str, int strLen, unsigned int hash) -{ - int ent = hash & (mHashTableSize-1); - - /* - * We over-allocate the table, so we're guaranteed to find an empty slot. - */ - while (mHashTable[ent].name != NULL) - ent = (ent + 1) & (mHashTableSize-1); - - mHashTable[ent].name = str; - mHashTable[ent].nameLen = strLen; -} - -/* - * Find a matching entry. - * - * Returns NULL if not found. - */ -ZipEntryRO ZipFileRO::findEntryByName(const char* fileName) const -{ - /* - * If the ZipFileRO instance is not initialized, the entry number will - * end up being garbage since mHashTableSize is -1. - */ - if (mHashTableSize <= 0) { - return NULL; - } - - int nameLen = strlen(fileName); - unsigned int hash = computeHash(fileName, nameLen); - int ent = hash & (mHashTableSize-1); - - while (mHashTable[ent].name != NULL) { - if (mHashTable[ent].nameLen == nameLen && - memcmp(mHashTable[ent].name, fileName, nameLen) == 0) - { - /* match */ - return (ZipEntryRO)(long)(ent + kZipEntryAdj); - } - - ent = (ent + 1) & (mHashTableSize-1); - } - - return NULL; -} - -/* - * Find the Nth entry. - * - * This currently involves walking through the sparse hash table, counting - * non-empty entries. If we need to speed this up we can either allocate - * a parallel lookup table or (perhaps better) provide an iterator interface. - */ -ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const -{ - if (idx < 0 || idx >= mNumEntries) { - ALOGW("Invalid index %d\n", idx); - return NULL; - } - - for (int ent = 0; ent < mHashTableSize; ent++) { - if (mHashTable[ent].name != NULL) { - if (idx-- == 0) - return (ZipEntryRO) (intptr_t)(ent + kZipEntryAdj); - } - } - - return NULL; -} - -/* - * Get the useful fields from the zip entry. - * - * Returns "false" if the offsets to the fields or the contents of the fields - * appear to be bogus. - */ -bool ZipFileRO::getEntryInfo(ZipEntryRO entry, int* pMethod, size_t* pUncompLen, - size_t* pCompLen, off64_t* pOffset, long* pModWhen, long* pCrc32) const -{ - bool ret = false; - - const int ent = entryToIndex(entry); - if (ent < 0) - return false; - - HashEntry hashEntry = mHashTable[ent]; - - /* - * Recover the start of the central directory entry from the filename - * pointer. The filename is the first entry past the fixed-size data, - * so we can just subtract back from that. - */ - const unsigned char* ptr = (const unsigned char*) hashEntry.name; - off64_t cdOffset = mDirectoryOffset; - - ptr -= kCDELen; - - int method = get2LE(ptr + kCDEMethod); - if (pMethod != NULL) - *pMethod = method; - - if (pModWhen != NULL) - *pModWhen = get4LE(ptr + kCDEModWhen); - if (pCrc32 != NULL) - *pCrc32 = get4LE(ptr + kCDECRC); - - size_t compLen = get4LE(ptr + kCDECompLen); - if (pCompLen != NULL) - *pCompLen = compLen; - size_t uncompLen = get4LE(ptr + kCDEUncompLen); - if (pUncompLen != NULL) - *pUncompLen = uncompLen; - - /* - * If requested, determine the offset of the start of the data. All we - * have is the offset to the Local File Header, which is variable size, - * so we have to read the contents of the struct to figure out where - * the actual data starts. - * - * We also need to make sure that the lengths are not so large that - * somebody trying to map the compressed or uncompressed data runs - * off the end of the mapped region. - * - * Note we don't verify compLen/uncompLen if they don't request the - * dataOffset, because dataOffset is expensive to determine. However, - * if they don't have the file offset, they're not likely to be doing - * anything with the contents. - */ - if (pOffset != NULL) { - long localHdrOffset = get4LE(ptr + kCDELocalOffset); - if (localHdrOffset + kLFHLen >= cdOffset) { - ALOGE("ERROR: bad local hdr offset in zip\n"); - return false; - } - - unsigned char lfhBuf[kLFHLen]; - -#ifdef HAVE_PREAD - /* - * This file descriptor might be from zygote's preloaded assets, - * so we need to do an pread64() instead of a lseek64() + read() to - * guarantee atomicity across the processes with the shared file - * descriptors. - */ - ssize_t actual = - TEMP_FAILURE_RETRY(pread64(mFd, lfhBuf, sizeof(lfhBuf), localHdrOffset)); - - if (actual != sizeof(lfhBuf)) { - ALOGW("failed reading lfh from offset %ld\n", localHdrOffset); - return false; - } - - if (get4LE(lfhBuf) != kLFHSignature) { - ALOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; " - "got: data=0x%08lx\n", - localHdrOffset, kLFHSignature, get4LE(lfhBuf)); - return false; - } -#else /* HAVE_PREAD */ - /* - * For hosts don't have pread64() we cannot guarantee atomic reads from - * an offset in a file. Android should never run on those platforms. - * File descriptors inherited from a fork() share file offsets and - * there would be nothing to protect from two different processes - * calling lseek64() concurrently. - */ - - { - AutoMutex _l(mFdLock); - - if (lseek64(mFd, localHdrOffset, SEEK_SET) != localHdrOffset) { - ALOGW("failed seeking to lfh at offset %ld\n", localHdrOffset); - return false; - } - - ssize_t actual = - TEMP_FAILURE_RETRY(read(mFd, lfhBuf, sizeof(lfhBuf))); - if (actual != sizeof(lfhBuf)) { - ALOGW("failed reading lfh from offset %ld\n", localHdrOffset); - return false; - } - - if (get4LE(lfhBuf) != kLFHSignature) { - off64_t actualOffset = lseek64(mFd, 0, SEEK_CUR); - ALOGW("didn't find signature at start of lfh; wanted: offset=%ld data=0x%08x; " - "got: offset=" ZD " data=0x%08lx\n", - localHdrOffset, kLFHSignature, (ZD_TYPE) actualOffset, get4LE(lfhBuf)); - return false; - } - } -#endif /* HAVE_PREAD */ - - off64_t dataOffset = localHdrOffset + kLFHLen - + get2LE(lfhBuf + kLFHNameLen) + get2LE(lfhBuf + kLFHExtraLen); - if (dataOffset >= cdOffset) { - ALOGW("bad data offset %ld in zip\n", (long) dataOffset); - return false; - } - - /* check lengths */ - if ((off64_t)(dataOffset + compLen) > cdOffset) { - ALOGW("bad compressed length in zip (%ld + " ZD " > %ld)\n", - (long) dataOffset, (ZD_TYPE) compLen, (long) cdOffset); - return false; - } - - if (method == kCompressStored && - (off64_t)(dataOffset + uncompLen) > cdOffset) - { - ALOGE("ERROR: bad uncompressed length in zip (%ld + " ZD " > %ld)\n", - (long) dataOffset, (ZD_TYPE) uncompLen, (long) cdOffset); - return false; - } - - *pOffset = dataOffset; - } - - return true; -} - -/* - * Copy the entry's filename to the buffer. - */ -int ZipFileRO::getEntryFileName(ZipEntryRO entry, char* buffer, int bufLen) - const -{ - int ent = entryToIndex(entry); - if (ent < 0) - return -1; - - int nameLen = mHashTable[ent].nameLen; - if (bufLen < nameLen+1) - return nameLen+1; - - memcpy(buffer, mHashTable[ent].name, nameLen); - buffer[nameLen] = '\0'; - return 0; -} - -/* - * Create a new FileMap object that spans the data in "entry". - */ -FileMap* ZipFileRO::createEntryFileMap(ZipEntryRO entry) const -{ - /* - * TODO: the efficient way to do this is to modify FileMap to allow - * sub-regions of a file to be mapped. A reference-counting scheme - * can manage the base memory mapping. For now, we just create a brand - * new mapping off of the Zip archive file descriptor. - */ - - FileMap* newMap; - size_t compLen; - off64_t offset; - - if (!getEntryInfo(entry, NULL, NULL, &compLen, &offset, NULL, NULL)) - return NULL; - - newMap = new FileMap(); - if (!newMap->create(mFileName, mFd, offset, compLen, true)) { - newMap->release(); - return NULL; - } - - return newMap; -} - -/* - * Uncompress an entry, in its entirety, into the provided output buffer. - * - * This doesn't verify the data's CRC, which might be useful for - * uncompressed data. The caller should be able to manage it. - */ -bool ZipFileRO::uncompressEntry(ZipEntryRO entry, void* buffer) const -{ - const size_t kSequentialMin = 32768; - bool result = false; - int ent = entryToIndex(entry); - if (ent < 0) - return -1; - - int method; - size_t uncompLen, compLen; - off64_t offset; - const unsigned char* ptr; - - getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL); - - FileMap* file = createEntryFileMap(entry); - if (file == NULL) { - goto bail; - } - - ptr = (const unsigned char*) file->getDataPtr(); - - /* - * Experiment with madvise hint. When we want to uncompress a file, - * we pull some stuff out of the central dir entry and then hit a - * bunch of compressed or uncompressed data sequentially. The CDE - * visit will cause a limited amount of read-ahead because it's at - * the end of the file. We could end up doing lots of extra disk - * access if the file we're prying open is small. Bottom line is we - * probably don't want to turn MADV_SEQUENTIAL on and leave it on. - * - * So, if the compressed size of the file is above a certain minimum - * size, temporarily boost the read-ahead in the hope that the extra - * pair of system calls are negated by a reduction in page faults. - */ - if (compLen > kSequentialMin) - file->advise(FileMap::SEQUENTIAL); - - if (method == kCompressStored) { - memcpy(buffer, ptr, uncompLen); - } else { - if (!inflateBuffer(buffer, ptr, uncompLen, compLen)) - goto unmap; - } - - if (compLen > kSequentialMin) - file->advise(FileMap::NORMAL); - - result = true; - -unmap: - file->release(); -bail: - return result; -} - -/* - * Uncompress an entry, in its entirety, to an open file descriptor. - * - * This doesn't verify the data's CRC, but probably should. - */ -bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const -{ - bool result = false; - int ent = entryToIndex(entry); - if (ent < 0) - return -1; - - int method; - size_t uncompLen, compLen; - off64_t offset; - const unsigned char* ptr; - - getEntryInfo(entry, &method, &uncompLen, &compLen, &offset, NULL, NULL); - - FileMap* file = createEntryFileMap(entry); - if (file == NULL) { - goto bail; - } - - ptr = (const unsigned char*) file->getDataPtr(); - - if (method == kCompressStored) { - ssize_t actual = TEMP_FAILURE_RETRY(write(fd, ptr, uncompLen)); - if (actual < 0) { - ALOGE("Write failed: %s\n", strerror(errno)); - goto unmap; - } else if ((size_t) actual != uncompLen) { - ALOGE("Partial write during uncompress (" ZD " of " ZD ")\n", - (ZD_TYPE) actual, (ZD_TYPE) uncompLen); - goto unmap; - } else { - ALOGI("+++ successful write\n"); - } - } else { - if (!inflateBuffer(fd, ptr, uncompLen, compLen)) - goto unmap; - } - - result = true; - -unmap: - file->release(); -bail: - return result; -} - -/* - * Uncompress "deflate" data from one buffer to another. - */ -/*static*/ bool ZipFileRO::inflateBuffer(void* outBuf, const void* inBuf, - size_t uncompLen, size_t compLen) -{ - bool result = false; - z_stream zstream; - int zerr; - - /* - * Initialize the zlib stream struct. - */ - memset(&zstream, 0, sizeof(zstream)); - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.next_in = (Bytef*)inBuf; - zstream.avail_in = compLen; - zstream.next_out = (Bytef*) outBuf; - zstream.avail_out = uncompLen; - zstream.data_type = Z_UNKNOWN; - - /* - * Use the undocumented "negative window bits" feature to tell zlib - * that there's no zlib header waiting for it. - */ - zerr = inflateInit2(&zstream, -MAX_WBITS); - if (zerr != Z_OK) { - if (zerr == Z_VERSION_ERROR) { - ALOGE("Installed zlib is not compatible with linked version (%s)\n", - ZLIB_VERSION); - } else { - ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr); - } - goto bail; - } - - /* - * Expand data. - */ - zerr = inflate(&zstream, Z_FINISH); - if (zerr != Z_STREAM_END) { - ALOGW("Zip inflate failed, zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n", - zerr, zstream.next_in, zstream.avail_in, - zstream.next_out, zstream.avail_out); - goto z_bail; - } - - /* paranoia */ - if (zstream.total_out != uncompLen) { - ALOGW("Size mismatch on inflated file (%ld vs " ZD ")\n", - zstream.total_out, (ZD_TYPE) uncompLen); - goto z_bail; - } - - result = true; - -z_bail: - inflateEnd(&zstream); /* free up any allocated structures */ - -bail: - return result; -} - -/* - * Uncompress "deflate" data from one buffer to an open file descriptor. - */ -/*static*/ bool ZipFileRO::inflateBuffer(int fd, const void* inBuf, - size_t uncompLen, size_t compLen) -{ - bool result = false; - const size_t kWriteBufSize = 32768; - unsigned char writeBuf[kWriteBufSize]; - z_stream zstream; - int zerr; - - /* - * Initialize the zlib stream struct. - */ - memset(&zstream, 0, sizeof(zstream)); - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.next_in = (Bytef*)inBuf; - zstream.avail_in = compLen; - zstream.next_out = (Bytef*) writeBuf; - zstream.avail_out = sizeof(writeBuf); - zstream.data_type = Z_UNKNOWN; - - /* - * Use the undocumented "negative window bits" feature to tell zlib - * that there's no zlib header waiting for it. - */ - zerr = inflateInit2(&zstream, -MAX_WBITS); - if (zerr != Z_OK) { - if (zerr == Z_VERSION_ERROR) { - ALOGE("Installed zlib is not compatible with linked version (%s)\n", - ZLIB_VERSION); - } else { - ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr); - } - goto bail; - } - - /* - * Loop while we have more to do. - */ - do { - /* - * Expand data. - */ - zerr = inflate(&zstream, Z_NO_FLUSH); - if (zerr != Z_OK && zerr != Z_STREAM_END) { - ALOGW("zlib inflate: zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)\n", - zerr, zstream.next_in, zstream.avail_in, - zstream.next_out, zstream.avail_out); - goto z_bail; - } - - /* write when we're full or when we're done */ - if (zstream.avail_out == 0 || - (zerr == Z_STREAM_END && zstream.avail_out != sizeof(writeBuf))) - { - long writeSize = zstream.next_out - writeBuf; - int cc = TEMP_FAILURE_RETRY(write(fd, writeBuf, writeSize)); - if (cc < 0) { - ALOGW("write failed in inflate: %s", strerror(errno)); - goto z_bail; - } else if (cc != (int) writeSize) { - ALOGW("write failed in inflate (%d vs %ld)", cc, writeSize); - goto z_bail; - } - - zstream.next_out = writeBuf; - zstream.avail_out = sizeof(writeBuf); - } - } while (zerr == Z_OK); - - assert(zerr == Z_STREAM_END); /* other errors should've been caught */ - - /* paranoia */ - if (zstream.total_out != uncompLen) { - ALOGW("Size mismatch on inflated file (%ld vs " ZD ")\n", - zstream.total_out, (ZD_TYPE) uncompLen); - goto z_bail; - } - - result = true; - -z_bail: - inflateEnd(&zstream); /* free up any allocated structures */ - -bail: - return result; -} diff --git a/libs/utils/ZipUtils.cpp b/libs/utils/ZipUtils.cpp deleted file mode 100644 index a43bbb0..0000000 --- a/libs/utils/ZipUtils.cpp +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -// -// Misc zip/gzip utility functions. -// - -#define LOG_TAG "ziputil" - -#include <utils/Log.h> -#include <utils/Compat.h> -#include <utils/ZipUtils.h> -#include <utils/ZipFileRO.h> - -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -#include <zlib.h> - -using namespace android; - -/* - * Utility function that expands zip/gzip "deflate" compressed data - * into a buffer. - * - * "fd" is an open file positioned at the start of the "deflate" data - * "buf" must hold at least "uncompressedLen" bytes. - */ -/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf, - long uncompressedLen, long compressedLen) -{ - bool result = false; - const unsigned long kReadBufSize = 32768; - unsigned char* readBuf = NULL; - z_stream zstream; - int zerr; - unsigned long compRemaining; - - assert(uncompressedLen >= 0); - assert(compressedLen >= 0); - - readBuf = new unsigned char[kReadBufSize]; - if (readBuf == NULL) - goto bail; - compRemaining = compressedLen; - - /* - * Initialize the zlib stream. - */ - memset(&zstream, 0, sizeof(zstream)); - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.next_in = NULL; - zstream.avail_in = 0; - zstream.next_out = (Bytef*) buf; - zstream.avail_out = uncompressedLen; - zstream.data_type = Z_UNKNOWN; - - /* - * Use the undocumented "negative window bits" feature to tell zlib - * that there's no zlib header waiting for it. - */ - zerr = inflateInit2(&zstream, -MAX_WBITS); - if (zerr != Z_OK) { - if (zerr == Z_VERSION_ERROR) { - ALOGE("Installed zlib is not compatible with linked version (%s)\n", - ZLIB_VERSION); - } else { - ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr); - } - goto bail; - } - - /* - * Loop while we have data. - */ - do { - unsigned long getSize; - - /* read as much as we can */ - if (zstream.avail_in == 0) { - getSize = (compRemaining > kReadBufSize) ? - kReadBufSize : compRemaining; - ALOGV("+++ reading %ld bytes (%ld left)\n", - getSize, compRemaining); - - int cc = TEMP_FAILURE_RETRY(read(fd, readBuf, getSize)); - if (cc < 0) { - ALOGW("inflate read failed: %s", strerror(errno)); - } else if (cc != (int) getSize) { - ALOGW("inflate read failed (%d vs %ld)", cc, getSize); - goto z_bail; - } - - compRemaining -= getSize; - - zstream.next_in = readBuf; - zstream.avail_in = getSize; - } - - /* uncompress the data */ - zerr = inflate(&zstream, Z_NO_FLUSH); - if (zerr != Z_OK && zerr != Z_STREAM_END) { - ALOGD("zlib inflate call failed (zerr=%d)\n", zerr); - goto z_bail; - } - - /* output buffer holds all, so no need to write the output */ - } while (zerr == Z_OK); - - assert(zerr == Z_STREAM_END); /* other errors should've been caught */ - - if ((long) zstream.total_out != uncompressedLen) { - ALOGW("Size mismatch on inflated file (%ld vs %ld)\n", - zstream.total_out, uncompressedLen); - goto z_bail; - } - - // success! - result = true; - -z_bail: - inflateEnd(&zstream); /* free up any allocated structures */ - -bail: - delete[] readBuf; - return result; -} - -/* - * Utility function that expands zip/gzip "deflate" compressed data - * into a buffer. - * - * (This is a clone of the previous function, but it takes a FILE* instead - * of an fd. We could pass fileno(fd) to the above, but we can run into - * trouble when "fp" has a different notion of what fd's file position is.) - * - * "fp" is an open file positioned at the start of the "deflate" data - * "buf" must hold at least "uncompressedLen" bytes. - */ -/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf, - long uncompressedLen, long compressedLen) -{ - bool result = false; - const unsigned long kReadBufSize = 32768; - unsigned char* readBuf = NULL; - z_stream zstream; - int zerr; - unsigned long compRemaining; - - assert(uncompressedLen >= 0); - assert(compressedLen >= 0); - - readBuf = new unsigned char[kReadBufSize]; - if (readBuf == NULL) - goto bail; - compRemaining = compressedLen; - - /* - * Initialize the zlib stream. - */ - memset(&zstream, 0, sizeof(zstream)); - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - zstream.next_in = NULL; - zstream.avail_in = 0; - zstream.next_out = (Bytef*) buf; - zstream.avail_out = uncompressedLen; - zstream.data_type = Z_UNKNOWN; - - /* - * Use the undocumented "negative window bits" feature to tell zlib - * that there's no zlib header waiting for it. - */ - zerr = inflateInit2(&zstream, -MAX_WBITS); - if (zerr != Z_OK) { - if (zerr == Z_VERSION_ERROR) { - ALOGE("Installed zlib is not compatible with linked version (%s)\n", - ZLIB_VERSION); - } else { - ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr); - } - goto bail; - } - - /* - * Loop while we have data. - */ - do { - unsigned long getSize; - - /* read as much as we can */ - if (zstream.avail_in == 0) { - getSize = (compRemaining > kReadBufSize) ? - kReadBufSize : compRemaining; - ALOGV("+++ reading %ld bytes (%ld left)\n", - getSize, compRemaining); - - int cc = fread(readBuf, 1, getSize, fp); - if (cc != (int) getSize) { - ALOGD("inflate read failed (%d vs %ld)\n", - cc, getSize); - goto z_bail; - } - - compRemaining -= getSize; - - zstream.next_in = readBuf; - zstream.avail_in = getSize; - } - - /* uncompress the data */ - zerr = inflate(&zstream, Z_NO_FLUSH); - if (zerr != Z_OK && zerr != Z_STREAM_END) { - ALOGD("zlib inflate call failed (zerr=%d)\n", zerr); - goto z_bail; - } - - /* output buffer holds all, so no need to write the output */ - } while (zerr == Z_OK); - - assert(zerr == Z_STREAM_END); /* other errors should've been caught */ - - if ((long) zstream.total_out != uncompressedLen) { - ALOGW("Size mismatch on inflated file (%ld vs %ld)\n", - zstream.total_out, uncompressedLen); - goto z_bail; - } - - // success! - result = true; - -z_bail: - inflateEnd(&zstream); /* free up any allocated structures */ - -bail: - delete[] readBuf; - return result; -} - -/* - * Look at the contents of a gzip archive. We want to know where the - * data starts, and how long it will be after it is uncompressed. - * - * We expect to find the CRC and length as the last 8 bytes on the file. - * This is a pretty reasonable thing to expect for locally-compressed - * files, but there's a small chance that some extra padding got thrown - * on (the man page talks about compressed data written to tape). We - * don't currently deal with that here. If "gzip -l" whines, we're going - * to fail too. - * - * On exit, "fp" is pointing at the start of the compressed data. - */ -/*static*/ bool ZipUtils::examineGzip(FILE* fp, int* pCompressionMethod, - long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32) -{ - enum { // flags - FTEXT = 0x01, - FHCRC = 0x02, - FEXTRA = 0x04, - FNAME = 0x08, - FCOMMENT = 0x10, - }; - int ic; - int method, flags; - int i; - - ic = getc(fp); - if (ic != 0x1f || getc(fp) != 0x8b) - return false; // not gzip - method = getc(fp); - flags = getc(fp); - - /* quick sanity checks */ - if (method == EOF || flags == EOF) - return false; - if (method != ZipFileRO::kCompressDeflated) - return false; - - /* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */ - for (i = 0; i < 6; i++) - (void) getc(fp); - /* consume "extra" field, if present */ - if ((flags & FEXTRA) != 0) { - int len; - - len = getc(fp); - len |= getc(fp) << 8; - while (len-- && getc(fp) != EOF) - ; - } - /* consume filename, if present */ - if ((flags & FNAME) != 0) { - do { - ic = getc(fp); - } while (ic != 0 && ic != EOF); - } - /* consume comment, if present */ - if ((flags & FCOMMENT) != 0) { - do { - ic = getc(fp); - } while (ic != 0 && ic != EOF); - } - /* consume 16-bit header CRC, if present */ - if ((flags & FHCRC) != 0) { - (void) getc(fp); - (void) getc(fp); - } - - if (feof(fp) || ferror(fp)) - return false; - - /* seek to the end; CRC and length are in the last 8 bytes */ - long curPosn = ftell(fp); - unsigned char buf[8]; - fseek(fp, -8, SEEK_END); - *pCompressedLen = ftell(fp) - curPosn; - - if (fread(buf, 1, 8, fp) != 8) - return false; - /* seek back to start of compressed data */ - fseek(fp, curPosn, SEEK_SET); - - *pCompressionMethod = method; - *pCRC32 = ZipFileRO::get4LE(&buf[0]); - *pUncompressedLen = ZipFileRO::get4LE(&buf[4]); - - return true; -} diff --git a/libs/utils/misc.cpp b/libs/utils/misc.cpp index 445a23a..58eb499 100644 --- a/libs/utils/misc.cpp +++ b/libs/utils/misc.cpp @@ -25,7 +25,6 @@ #include <sys/stat.h> #include <string.h> #include <errno.h> -#include <assert.h> #include <stdio.h> #if defined(HAVE_PTHREADS) @@ -38,56 +37,6 @@ using namespace android; namespace android { -/* - * Get a file's type. - */ -FileType getFileType(const char* fileName) -{ - struct stat sb; - - if (stat(fileName, &sb) < 0) { - if (errno == ENOENT || errno == ENOTDIR) - return kFileTypeNonexistent; - else { - fprintf(stderr, "getFileType got errno=%d on '%s'\n", - errno, fileName); - return kFileTypeUnknown; - } - } else { - if (S_ISREG(sb.st_mode)) - return kFileTypeRegular; - else if (S_ISDIR(sb.st_mode)) - return kFileTypeDirectory; - else if (S_ISCHR(sb.st_mode)) - return kFileTypeCharDev; - else if (S_ISBLK(sb.st_mode)) - return kFileTypeBlockDev; - else if (S_ISFIFO(sb.st_mode)) - return kFileTypeFifo; -#ifdef HAVE_SYMLINKS - else if (S_ISLNK(sb.st_mode)) - return kFileTypeSymlink; - else if (S_ISSOCK(sb.st_mode)) - return kFileTypeSocket; -#endif - else - return kFileTypeUnknown; - } -} - -/* - * Get a file's modification date. - */ -time_t getFileModDate(const char* fileName) -{ - struct stat sb; - - if (stat(fileName, &sb) < 0) - return (time_t) -1; - - return sb.st_mtime; -} - struct sysprop_change_callback_info { sysprop_change_callback callback; int priority; diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk index a2ca9c8..caedaff 100644 --- a/libs/utils/tests/Android.mk +++ b/libs/utils/tests/Android.mk @@ -6,12 +6,12 @@ include $(CLEAR_VARS) test_src_files := \ BasicHashtable_test.cpp \ BlobCache_test.cpp \ + BitSet_test.cpp \ Looper_test.cpp \ LruCache_test.cpp \ String8_test.cpp \ Unicode_test.cpp \ - Vector_test.cpp \ - ZipFileRO_test.cpp + Vector_test.cpp shared_libraries := \ libz \ diff --git a/libs/utils/tests/BitSet_test.cpp b/libs/utils/tests/BitSet_test.cpp new file mode 100644 index 0000000..752e56d --- /dev/null +++ b/libs/utils/tests/BitSet_test.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2013 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. + */ + +#define LOG_TAG "BitSet_test" + +#include <utils/BitSet.h> +#include <cutils/log.h> +#include <gtest/gtest.h> +#include <unistd.h> + +namespace android { + +class BitSetTest : public testing::Test { +protected: + BitSet32 b1; + BitSet32 b2; + virtual void TearDown() { + b1.clear(); + b2.clear(); + } +}; + + +TEST_F(BitSetTest, BitWiseOr) { + b1.markBit(2); + b2.markBit(4); + + BitSet32 tmp = b1 | b2; + EXPECT_EQ(tmp.count(), 2u); + EXPECT_TRUE(tmp.hasBit(2) && tmp.hasBit(4)); + // Check that the operator is symmetric + EXPECT_TRUE((b2 | b1) == (b1 | b2)); + + b1 |= b2; + EXPECT_EQ(b1.count(), 2u); + EXPECT_TRUE(b1.hasBit(2) && b1.hasBit(4)); + EXPECT_TRUE(b2.hasBit(4) && b2.count() == 1u); +} +TEST_F(BitSetTest, BitWiseAnd_Disjoint) { + b1.markBit(2); + b1.markBit(4); + b1.markBit(6); + + BitSet32 tmp = b1 & b2; + EXPECT_TRUE(tmp.isEmpty()); + // Check that the operator is symmetric + EXPECT_TRUE((b2 & b1) == (b1 & b2)); + + b2 &= b1; + EXPECT_TRUE(b2.isEmpty()); + EXPECT_EQ(b1.count(), 3u); + EXPECT_TRUE(b1.hasBit(2) && b1.hasBit(4) && b1.hasBit(6)); +} + +TEST_F(BitSetTest, BitWiseAnd_NonDisjoint) { + b1.markBit(2); + b1.markBit(4); + b1.markBit(6); + b2.markBit(3); + b2.markBit(6); + b2.markBit(9); + + BitSet32 tmp = b1 & b2; + EXPECT_EQ(tmp.count(), 1u); + EXPECT_TRUE(tmp.hasBit(6)); + // Check that the operator is symmetric + EXPECT_TRUE((b2 & b1) == (b1 & b2)); + + b1 &= b2; + EXPECT_EQ(b1.count(), 1u); + EXPECT_EQ(b2.count(), 3u); + EXPECT_TRUE(b2.hasBit(3) && b2.hasBit(6) && b2.hasBit(9)); +} +} // namespace android diff --git a/libs/utils/tests/ZipFileRO_test.cpp b/libs/utils/tests/ZipFileRO_test.cpp deleted file mode 100644 index 7a1d0bd..0000000 --- a/libs/utils/tests/ZipFileRO_test.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -#define LOG_TAG "ZipFileRO_test" -#include <utils/Log.h> -#include <utils/ZipFileRO.h> - -#include <gtest/gtest.h> - -#include <fcntl.h> -#include <string.h> - -namespace android { - -class ZipFileROTest : public testing::Test { -protected: - virtual void SetUp() { - } - - virtual void TearDown() { - } -}; - -TEST_F(ZipFileROTest, ZipTimeConvertSuccess) { - struct tm t; - - // 2011-06-29 14:40:40 - long when = 0x3EDD7514; - - ZipFileRO::zipTimeToTimespec(when, &t); - - EXPECT_EQ(2011, t.tm_year + 1900) - << "Year was improperly converted."; - - EXPECT_EQ(6, t.tm_mon) - << "Month was improperly converted."; - - EXPECT_EQ(29, t.tm_mday) - << "Day was improperly converted."; - - EXPECT_EQ(14, t.tm_hour) - << "Hour was improperly converted."; - - EXPECT_EQ(40, t.tm_min) - << "Minute was improperly converted."; - - EXPECT_EQ(40, t.tm_sec) - << "Second was improperly converted."; -} - -} diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 00bfa5a..c02a85f 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -21,6 +21,7 @@ #include <errno.h> #include <dlfcn.h> #include <limits.h> +#include <dirent.h> #include <cutils/log.h> #include <cutils/properties.h> @@ -38,9 +39,25 @@ namespace android { /* - * EGL drivers are called + * EGL userspace drivers must be provided either: + * - as a single library: + * /vendor/lib/egl/libGLES.so + * + * - as separate libraries: + * /vendor/lib/egl/libEGL.so + * /vendor/lib/egl/libGLESv1_CM.so + * /vendor/lib/egl/libGLESv2.so + * + * The software renderer for the emulator must be provided as a single + * library at: + * + * /system/lib/egl/libGLES_android.so + * + * + * For backward compatibility and to facilitate the transition to + * this new naming scheme, the loader will additionally look for: * - * /system/lib/egl/lib{[EGL|GLESv1_CM|GLESv2] | GLES}_$TAG.so + * /{vendor|system}/lib/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_*.so * */ @@ -137,41 +154,10 @@ status_t Loader::driver_t::set(void* hnd, int32_t api) // ---------------------------------------------------------------------------- Loader::Loader() -{ - char line[256]; - char tag[256]; - - /* Special case for GLES emulation */ - if (checkGlesEmulationStatus() == 0) { - ALOGD("Emulator without GPU support detected. " - "Fallback to software renderer."); - mDriverTag.setTo("android"); - return; - } - - /* Otherwise, use egl.cfg */ - FILE* cfg = fopen("/system/lib/egl/egl.cfg", "r"); - if (cfg == NULL) { - // default config - ALOGD("egl.cfg not found, using default config"); - mDriverTag.setTo("android"); - } else { - while (fgets(line, 256, cfg)) { - int dpy, impl; - if (sscanf(line, "%u %u %s", &dpy, &impl, tag) == 3) { - //ALOGD(">>> %u %u %s", dpy, impl, tag); - // We only load the h/w accelerated implementation - if (tag != String8("android")) { - mDriverTag = tag; - } - } - } - fclose(cfg); - } + : getProcAddress(NULL) { } -Loader::~Loader() -{ +Loader::~Loader() { GLTrace_stop(); } @@ -180,26 +166,20 @@ void* Loader::open(egl_connection_t* cnx) void* dso; driver_t* hnd = 0; - char const* tag = mDriverTag.string(); - if (tag) { - dso = load_driver("GLES", tag, cnx, EGL | GLESv1_CM | GLESv2); + dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2); + if (dso) { + hnd = new driver_t(dso); + } else { + // Always load EGL first + dso = load_driver("EGL", cnx, EGL); if (dso) { hnd = new driver_t(dso); - } else { - // Always load EGL first - dso = load_driver("EGL", tag, cnx, EGL); - if (dso) { - hnd = new driver_t(dso); - // TODO: make this more automated - hnd->set( load_driver("GLESv1_CM", tag, cnx, GLESv1_CM), GLESv1_CM ); - hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 ); - } + hnd->set( load_driver("GLESv1_CM", cnx, GLESv1_CM), GLESv1_CM ); + hnd->set( load_driver("GLESv2", cnx, GLESv2), GLESv2 ); } } - LOG_FATAL_IF(!index && !hnd, - "couldn't find the default OpenGL ES implementation " - "for default display"); + LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation"); return (void*)hnd; } @@ -267,21 +247,106 @@ void Loader::init_api(void* dso, } } -void *Loader::load_driver(const char* kind, const char *tag, +void *Loader::load_driver(const char* kind, egl_connection_t* cnx, uint32_t mask) { - char driver_absolute_path[PATH_MAX]; - const char* const search1 = "/vendor/lib/egl/lib%s_%s.so"; - const char* const search2 = "/system/lib/egl/lib%s_%s.so"; - - snprintf(driver_absolute_path, PATH_MAX, search1, kind, tag); - if (access(driver_absolute_path, R_OK)) { - snprintf(driver_absolute_path, PATH_MAX, search2, kind, tag); - if (access(driver_absolute_path, R_OK)) { - // this happens often, we don't want to log an error - return 0; + class MatchFile { + public: + static String8 find(const char* kind) { + String8 result; + String8 pattern; + pattern.appendFormat("lib%s", kind); + const char* const searchPaths[] = { + "/vendor/lib/egl", + "/system/lib/egl" + }; + + // first, we search for the exact name of the GLES userspace + // driver in both locations. + // i.e.: + // libGLES.so, or: + // libEGL.so, libGLESv1_CM.so, libGLESv2.so + + for (size_t i=0 ; i<NELEM(searchPaths) ; i++) { + if (find(result, pattern, searchPaths[i], true)) { + return result; + } + } + + // for compatibility with the old "egl.cfg" naming convention + // we look for files that match: + // libGLES_*.so, or: + // libEGL_*.so, libGLESv1_CM_*.so, libGLESv2_*.so + + pattern.append("_"); + for (size_t i=0 ; i<NELEM(searchPaths) ; i++) { + if (find(result, pattern, searchPaths[i], false)) { + return result; + } + } + + // we didn't find the driver. gah. + result.clear(); + return result; } + + private: + static bool find(String8& result, + const String8& pattern, const char* const search, bool exact) { + + // in the emulator case, we just return the hardcoded name + // of the software renderer. + if (checkGlesEmulationStatus() == 0) { + ALOGD("Emulator without GPU support detected. " + "Fallback to software renderer."); + result.setTo("/system/lib/egl/libGLES_android.so"); + return true; + } + + if (exact) { + String8 absolutePath; + absolutePath.appendFormat("%s/%s.so", search, pattern.string()); + if (!access(absolutePath.string(), R_OK)) { + result = absolutePath; + return true; + } + return false; + } + + DIR* d = opendir(search); + if (d != NULL) { + struct dirent cur; + struct dirent* e; + while (readdir_r(d, &cur, &e) == 0 && e) { + if (e->d_type == DT_DIR) { + continue; + } + if (!strcmp(e->d_name, "libGLES_android.so")) { + // always skip the software renderer + continue; + } + if (strstr(e->d_name, pattern.string()) == e->d_name) { + if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) { + result.clear(); + result.appendFormat("%s/%s", search, e->d_name); + closedir(d); + return true; + } + } + } + closedir(d); + } + return false; + } + }; + + + String8 absolutePath = MatchFile::find(kind); + if (absolutePath.isEmpty()) { + // this happens often, we don't want to log an error + return 0; } + const char* const driver_absolute_path = absolutePath.string(); void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL); if (dso == 0) { diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h index 30773cb..8cefe32 100644 --- a/opengl/libs/EGL/Loader.h +++ b/opengl/libs/EGL/Loader.h @@ -52,7 +52,6 @@ class Loader : public Singleton<Loader> void* dso[3]; }; - String8 mDriverTag; getProcAddressType getProcAddress; public: @@ -63,7 +62,7 @@ public: private: Loader(); - void *load_driver(const char* kind, const char *tag, egl_connection_t* cnx, uint32_t mask); + void *load_driver(const char* kind, egl_connection_t* cnx, uint32_t mask); static __attribute__((noinline)) void init_api(void* dso, diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 93eedff..2bc9851 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -1182,6 +1182,11 @@ EGLBoolean eglReleaseThread(void) { clearError(); +#if EGL_TRACE + if (getEGLDebugLevel() > 0) + GLTrace_eglReleaseThread(); +#endif + // If there is context bound to the thread, release it egl_display_t::loseCurrent(get_context(getContext())); @@ -1189,12 +1194,7 @@ EGLBoolean eglReleaseThread(void) if (cnx->dso && cnx->egl.eglReleaseThread) { cnx->egl.eglReleaseThread(); } - egl_tls_t::clearTLS(); -#if EGL_TRACE - if (getEGLDebugLevel() > 0) - GLTrace_eglReleaseThread(); -#endif return EGL_TRUE; } diff --git a/opengl/libs/EGL/egl_tls.cpp b/opengl/libs/EGL/egl_tls.cpp index 52312a2..f3739aa 100644 --- a/opengl/libs/EGL/egl_tls.cpp +++ b/opengl/libs/EGL/egl_tls.cpp @@ -29,8 +29,8 @@ namespace android { -pthread_key_t egl_tls_t::sKey = -1; -pthread_mutex_t egl_tls_t::sLockKey = PTHREAD_MUTEX_INITIALIZER; +pthread_key_t egl_tls_t::sKey = TLS_KEY_NOT_INITIALIZED; +pthread_once_t egl_tls_t::sOnceKey = PTHREAD_ONCE_INIT; egl_tls_t::egl_tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { @@ -59,12 +59,12 @@ const char *egl_tls_t::egl_strerror(EGLint err) { void egl_tls_t::validateTLSKey() { - if (sKey == -1) { - pthread_mutex_lock(&sLockKey); - if (sKey == -1) - pthread_key_create(&sKey, NULL); - pthread_mutex_unlock(&sLockKey); - } + struct TlsKeyInitializer { + static void create() { + pthread_key_create(&sKey, (void (*)(void*))&eglReleaseThread); + } + }; + pthread_once(&sOnceKey, TlsKeyInitializer::create); } void egl_tls_t::setErrorEtcImpl( @@ -104,11 +104,11 @@ egl_tls_t* egl_tls_t::getTLS() { } void egl_tls_t::clearTLS() { - if (sKey != -1) { + if (sKey != TLS_KEY_NOT_INITIALIZED) { egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey); if (tls) { - delete tls; pthread_setspecific(sKey, 0); + delete tls; } } } @@ -120,10 +120,13 @@ void egl_tls_t::clearError() { } EGLint egl_tls_t::getError() { - if (sKey == -1) + if (sKey == TLS_KEY_NOT_INITIALIZED) { return EGL_SUCCESS; + } egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey); - if (!tls) return EGL_SUCCESS; + if (!tls) { + return EGL_SUCCESS; + } EGLint error = tls->error; tls->error = EGL_SUCCESS; return error; @@ -135,8 +138,9 @@ void egl_tls_t::setContext(EGLContext ctx) { } EGLContext egl_tls_t::getContext() { - if (sKey == -1) + if (sKey == TLS_KEY_NOT_INITIALIZED) { return EGL_NO_CONTEXT; + } egl_tls_t* tls = (egl_tls_t *)pthread_getspecific(sKey); if (!tls) return EGL_NO_CONTEXT; return tls->ctx; diff --git a/opengl/libs/EGL/egl_tls.h b/opengl/libs/EGL/egl_tls.h index 56c5dba..5af4f5b 100644 --- a/opengl/libs/EGL/egl_tls.h +++ b/opengl/libs/EGL/egl_tls.h @@ -30,8 +30,9 @@ namespace android { class DbgContext; class egl_tls_t { + enum { TLS_KEY_NOT_INITIALIZED = -1 }; static pthread_key_t sKey; - static pthread_mutex_t sLockKey; + static pthread_once_t sOnceKey; EGLint error; EGLContext ctx; diff --git a/opengl/libs/GLES_trace/src/gltrace_context.cpp b/opengl/libs/GLES_trace/src/gltrace_context.cpp index 3a8decc..0323e8f 100644 --- a/opengl/libs/GLES_trace/src/gltrace_context.cpp +++ b/opengl/libs/GLES_trace/src/gltrace_context.cpp @@ -32,7 +32,7 @@ static pthread_key_t sTLSKey = -1; static pthread_once_t sPthreadOnceKey = PTHREAD_ONCE_INIT; void createTLSKey() { - pthread_key_create(&sTLSKey, NULL); + pthread_key_create(&sTLSKey, (void (*)(void*))&releaseContext); } GLTraceContext *getGLTraceContext() { diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen index d236c1e..7146a29 100755 --- a/opengl/tools/glgen/gen +++ b/opengl/tools/glgen/gen @@ -32,10 +32,6 @@ echo "package android.os; public class RemoteException extends Exception {}" > o echo "package android.util; public class Log {public static void w(String a, String b) {} public static void e(String a, String b) {}}" > out/android/util/Log.java echo "package android.opengl; public abstract class EGLObjectHandle { public int getHandle() { return 0; } }" > out/android/opengl/EGLObjectHandle.java -echo "package android.opengl; public class EGLSurface extends EGLObjectHandle { }" > out/android/opengl/EGLSurface.java -echo "package android.opengl; public class EGLContext extends EGLObjectHandle { }" > out/android/opengl/EGLContext.java -echo "package android.opengl; public class EGLDisplay extends EGLObjectHandle { }" > out/android/opengl/EGLDisplay.java -echo "package android.opengl; public class EGLConfig extends EGLObjectHandle { }" > out/android/opengl/EGLConfig.java echo "package android.graphics;" > out/android/graphics/SurfaceTexture.java @@ -47,6 +43,7 @@ echo "public interface Surface {}" >> out/android/view/Surface.java echo "package android.view;" > out/android/view/SurfaceHolder.java echo "public interface SurfaceHolder { Surface getSurface(); }" >> out/android/view/SurfaceHolder.java +cp static/egl/*.java out/android/opengl/ GLFILE=out/javax/microedition/khronos/opengles/GL.java cp stubs/jsr239/GLHeader.java-if $GLFILE @@ -141,8 +138,8 @@ compareGenerated() { echo SAID_PLEASE=1 fi - echo " " cp $2/$3 $1 - echo " " git add $1/$3 + echo " cp $2/$3 $1" + echo " (cd $1; git add $3)" KEEP_GENERATED=1 fi } @@ -161,6 +158,11 @@ do compareGenerated ../../../../base/core/jni generated/C android_opengl_${x}.cpp done +for x in EGLConfig EGLContext EGLDisplay EGLObjectHandle EGLSurface +do + compareGenerated ../../../../base/opengl/java/android/opengl generated/android/opengl ${x}.java +done + if [ $KEEP_GENERATED == "0" ] ; then rm -rf generated fi diff --git a/opengl/tools/glgen/static/egl/EGLConfig.java b/opengl/tools/glgen/static/egl/EGLConfig.java index d457c9f..a7a6bbb 100644 --- a/opengl/tools/glgen/static/egl/EGLConfig.java +++ b/opengl/tools/glgen/static/egl/EGLConfig.java @@ -29,7 +29,7 @@ public class EGLConfig extends EGLObjectHandle { @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (!(o instanceof EGLConfig)) return false; EGLConfig that = (EGLConfig) o; return getHandle() == that.getHandle(); diff --git a/opengl/tools/glgen/static/egl/EGLContext.java b/opengl/tools/glgen/static/egl/EGLContext.java index 41b8ef1..c93bd6e 100644 --- a/opengl/tools/glgen/static/egl/EGLContext.java +++ b/opengl/tools/glgen/static/egl/EGLContext.java @@ -29,7 +29,7 @@ public class EGLContext extends EGLObjectHandle { @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (!(o instanceof EGLContext)) return false; EGLContext that = (EGLContext) o; return getHandle() == that.getHandle(); diff --git a/opengl/tools/glgen/static/egl/EGLDisplay.java b/opengl/tools/glgen/static/egl/EGLDisplay.java index 17d1a64..5b8043a 100644 --- a/opengl/tools/glgen/static/egl/EGLDisplay.java +++ b/opengl/tools/glgen/static/egl/EGLDisplay.java @@ -29,7 +29,7 @@ public class EGLDisplay extends EGLObjectHandle { @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (!(o instanceof EGLDisplay)) return false; EGLDisplay that = (EGLDisplay) o; return getHandle() == that.getHandle(); diff --git a/opengl/tools/glgen/static/egl/EGLSurface.java b/opengl/tools/glgen/static/egl/EGLSurface.java index 65bec4f..c379dc9 100644 --- a/opengl/tools/glgen/static/egl/EGLSurface.java +++ b/opengl/tools/glgen/static/egl/EGLSurface.java @@ -29,7 +29,7 @@ public class EGLSurface extends EGLObjectHandle { @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (!(o instanceof EGLSurface)) return false; EGLSurface that = (EGLSurface) o; return getHandle() == that.getHandle(); diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp index 579d573..75b75cb 100644 --- a/opengl/tools/glgen/stubs/gles11/common.cpp +++ b/opengl/tools/glgen/stubs/gles11/common.cpp @@ -272,6 +272,7 @@ getarray int _needed = 0; params = (CTYPE *)getPointer(_env, params_buf, &_array, &_remaining, &_bufferOffset); + _remaining /= sizeof(CTYPE); // convert from bytes to item count _needed = getNeededCount(pname); // if we didn't find this pname, we just assume the user passed // an array of the right size -- this might happen with extensions diff --git a/services/powermanager/IPowerManager.cpp b/services/powermanager/IPowerManager.cpp index 0265df3..3f5b81e 100644 --- a/services/powermanager/IPowerManager.cpp +++ b/services/powermanager/IPowerManager.cpp @@ -41,7 +41,8 @@ public: { } - virtual status_t acquireWakeLock(int flags, const sp<IBinder>& lock, const String16& tag) + virtual status_t acquireWakeLock(int flags, const sp<IBinder>& lock, const String16& tag, + const String16& packageName) { Parcel data, reply; data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor()); @@ -49,6 +50,7 @@ public: data.writeStrongBinder(lock); data.writeInt32(flags); data.writeString16(tag); + data.writeString16(packageName); data.writeInt32(0); // no WorkSource return remote()->transact(ACQUIRE_WAKE_LOCK, data, &reply); } diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk index dd698c5..14a4e55 100644 --- a/services/sensorservice/Android.mk +++ b/services/sensorservice/Android.mk @@ -12,11 +12,12 @@ LOCAL_SRC_FILES:= \ SensorDevice.cpp \ SensorFusion.cpp \ SensorInterface.cpp \ - SensorService.cpp \ - + SensorService.cpp LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\" +LOCAL_CFLAGS += -fvisibility=hidden + LOCAL_SHARED_LIBRARIES := \ libcutils \ libhardware \ @@ -27,8 +28,6 @@ LOCAL_SHARED_LIBRARIES := \ libui \ libgui - - LOCAL_MODULE:= libsensorservice include $(BUILD_SHARED_LIBRARY) diff --git a/services/sensorservice/CorrectedGyroSensor.cpp b/services/sensorservice/CorrectedGyroSensor.cpp index 1857443..09f60a9 100644 --- a/services/sensorservice/CorrectedGyroSensor.cpp +++ b/services/sensorservice/CorrectedGyroSensor.cpp @@ -69,7 +69,7 @@ status_t CorrectedGyroSensor::setDelay(void* ident, int handle, int64_t ns) { Sensor CorrectedGyroSensor::getSensor() const { sensor_t hwSensor; hwSensor.name = "Corrected Gyroscope Sensor"; - hwSensor.vendor = "Google Inc."; + hwSensor.vendor = "AOSP"; hwSensor.version = 1; hwSensor.handle = '_cgy'; hwSensor.type = SENSOR_TYPE_GYROSCOPE; diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp index 93d6127..4f63c31 100644 --- a/services/sensorservice/Fusion.cpp +++ b/services/sensorservice/Fusion.cpp @@ -220,22 +220,6 @@ void Fusion::initFusion(const vec4_t& q, float dT) // initial covariance: Var{ x(t0) } // TODO: initialize P correctly P = 0; - - // it is unclear how to set the initial covariance. It does affect - // how quickly the fusion converges. Experimentally it would take - // about 10 seconds at 200 Hz to estimate the gyro-drift with an - // initial covariance of 0, and about a second with an initial covariance - // of about 1 deg/s. - const float covv = 0; - const float covu = 0.5f * (float(M_PI) / 180); - mat33_t& Pv = P[0][0]; - Pv[0][0] = covv; - Pv[1][1] = covv; - Pv[2][2] = covv; - mat33_t& Pu = P[1][1]; - Pu[0][0] = covu; - Pu[1][1] = covu; - Pu[2][2] = covu; } bool Fusion::hasEstimate() const { diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp index c57715f..0bf20db 100644 --- a/services/sensorservice/GravitySensor.cpp +++ b/services/sensorservice/GravitySensor.cpp @@ -77,7 +77,7 @@ status_t GravitySensor::setDelay(void* ident, int handle, int64_t ns) { Sensor GravitySensor::getSensor() const { sensor_t hwSensor; hwSensor.name = "Gravity Sensor"; - hwSensor.vendor = "Google Inc."; + hwSensor.vendor = "AOSP"; hwSensor.version = 3; hwSensor.handle = '_grv'; hwSensor.type = SENSOR_TYPE_GRAVITY; diff --git a/services/sensorservice/LinearAccelerationSensor.cpp b/services/sensorservice/LinearAccelerationSensor.cpp index f0054f2..25ae473 100644 --- a/services/sensorservice/LinearAccelerationSensor.cpp +++ b/services/sensorservice/LinearAccelerationSensor.cpp @@ -62,7 +62,7 @@ Sensor LinearAccelerationSensor::getSensor() const { Sensor gsensor(mGravitySensor.getSensor()); sensor_t hwSensor; hwSensor.name = "Linear Acceleration Sensor"; - hwSensor.vendor = "Google Inc."; + hwSensor.vendor = "AOSP"; hwSensor.version = gsensor.getVersion(); hwSensor.handle = '_lin'; hwSensor.type = SENSOR_TYPE_LINEAR_ACCELERATION; diff --git a/services/sensorservice/OrientationSensor.cpp b/services/sensorservice/OrientationSensor.cpp index 037adaa..b146332 100644 --- a/services/sensorservice/OrientationSensor.cpp +++ b/services/sensorservice/OrientationSensor.cpp @@ -33,6 +33,9 @@ OrientationSensor::OrientationSensor() : mSensorDevice(SensorDevice::getInstance()), mSensorFusion(SensorFusion::getInstance()) { + // FIXME: instead of using the SensorFusion code, we should use + // the SENSOR_TYPE_ROTATION_VECTOR instead. This way we could use the + // HAL's implementation. } bool OrientationSensor::process(sensors_event_t* outEvent, @@ -73,7 +76,7 @@ status_t OrientationSensor::setDelay(void* ident, int handle, int64_t ns) { Sensor OrientationSensor::getSensor() const { sensor_t hwSensor; hwSensor.name = "Orientation Sensor"; - hwSensor.vendor = "Google Inc."; + hwSensor.vendor = "AOSP"; hwSensor.version = 1; hwSensor.handle = '_ypr'; hwSensor.type = SENSOR_TYPE_ORIENTATION; diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp index 5ea9568..725deb4 100644 --- a/services/sensorservice/RotationVectorSensor.cpp +++ b/services/sensorservice/RotationVectorSensor.cpp @@ -63,7 +63,7 @@ status_t RotationVectorSensor::setDelay(void* ident, int handle, int64_t ns) { Sensor RotationVectorSensor::getSensor() const { sensor_t hwSensor; hwSensor.name = "Rotation Vector Sensor"; - hwSensor.vendor = "Google Inc."; + hwSensor.vendor = "AOSP"; hwSensor.version = 3; hwSensor.handle = '_rov'; hwSensor.type = SENSOR_TYPE_ROTATION_VECTOR; @@ -112,7 +112,7 @@ status_t GyroDriftSensor::setDelay(void* ident, int handle, int64_t ns) { Sensor GyroDriftSensor::getSensor() const { sensor_t hwSensor; hwSensor.name = "Gyroscope Bias (debug)"; - hwSensor.vendor = "Google Inc."; + hwSensor.vendor = "AOSP"; hwSensor.version = 1; hwSensor.handle = '_gbs'; hwSensor.type = SENSOR_TYPE_ACCELEROMETER; diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp index d23906d..a0a17da 100644 --- a/services/sensorservice/SensorFusion.cpp +++ b/services/sensorservice/SensorFusion.cpp @@ -28,6 +28,7 @@ SensorFusion::SensorFusion() mEnabled(false), mGyroTime(0) { sensor_t const* list; + Sensor uncalibratedGyro; ssize_t count = mSensorDevice.getSensorList(&list); if (count > 0) { for (size_t i=0 ; i<size_t(count) ; i++) { @@ -39,28 +40,38 @@ SensorFusion::SensorFusion() } if (list[i].type == SENSOR_TYPE_GYROSCOPE) { mGyro = Sensor(list + i); - // 200 Hz for gyro events is a good compromise between precision - // and power/cpu usage. - mGyroRate = 200; - mTargetDelayNs = 1000000000LL/mGyroRate; } + if (list[i].type == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) { + uncalibratedGyro = Sensor(list + i); + } + } + + // Use the uncalibrated gyroscope for sensor fusion when available + if (uncalibratedGyro.getType() == SENSOR_TYPE_GYROSCOPE_UNCALIBRATED) { + mGyro = uncalibratedGyro; } + + // 200 Hz for gyro events is a good compromise between precision + // and power/cpu usage. + mEstimatedGyroRate = 200; + mTargetDelayNs = 1000000000LL/mEstimatedGyroRate; mFusion.init(); } } void SensorFusion::process(const sensors_event_t& event) { - if (event.type == SENSOR_TYPE_GYROSCOPE) { + if (event.type == mGyro.getType()) { if (mGyroTime != 0) { const float dT = (event.timestamp - mGyroTime) / 1000000000.0f; + mFusion.handleGyro(vec3_t(event.data), dT); + // here we estimate the gyro rate (useful for debugging) const float freq = 1 / dT; if (freq >= 100 && freq<1000) { // filter values obviously wrong const float alpha = 1 / (1 + dT); // 1s time-constant - mGyroRate = freq + (mGyroRate - freq)*alpha; + mEstimatedGyroRate = freq + (mEstimatedGyroRate - freq)*alpha; } } mGyroTime = event.timestamp; - mFusion.handleGyro(vec3_t(event.data), 1.0f/mGyroRate); } else if (event.type == SENSOR_TYPE_MAGNETIC_FIELD) { const vec3_t mag(event.data); mFusion.handleMag(mag); @@ -132,7 +143,7 @@ void SensorFusion::dump(String8& result, char* buffer, size_t SIZE) { "b=< %g, %g, %g >\n", mEnabled ? "enabled" : "disabled", mClients.size(), - mGyroRate, + mEstimatedGyroRate, fusion.getAttitude().x, fusion.getAttitude().y, fusion.getAttitude().z, diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h index 4c99bcb..3c2244e 100644 --- a/services/sensorservice/SensorFusion.h +++ b/services/sensorservice/SensorFusion.h @@ -44,7 +44,7 @@ class SensorFusion : public Singleton<SensorFusion> { Sensor mGyro; Fusion mFusion; bool mEnabled; - float mGyroRate; + float mEstimatedGyroRate; nsecs_t mTargetDelayNs; nsecs_t mGyroTime; vec4_t mAttitude; @@ -60,7 +60,7 @@ public: mat33_t getRotationMatrix() const { return mFusion.getRotationMatrix(); } vec4_t getAttitude() const { return mAttitude; } vec3_t getGyroBias() const { return mFusion.getBias(); } - float getEstimatedRate() const { return mGyroRate; } + float getEstimatedRate() const { return mEstimatedGyroRate; } status_t activate(void* ident, bool enabled); status_t setDelay(void* ident, int64_t ns); diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index ebf5cf0..4718447 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -93,6 +93,7 @@ void SensorService::onFirstRef() orientationIndex = i; break; case SENSOR_TYPE_GYROSCOPE: + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: hasGyro = true; break; case SENSOR_TYPE_GRAVITY: @@ -108,54 +109,44 @@ void SensorService::onFirstRef() // registered) const SensorFusion& fusion(SensorFusion::getInstance()); + // build the sensor list returned to users + mUserSensorList = mSensorList; + if (hasGyro) { - // Always instantiate Android's virtual sensors. Since they are - // instantiated behind sensors from the HAL, they won't - // interfere with applications, unless they looks specifically - // for them (by name). + Sensor aSensor; - registerVirtualSensor( new RotationVectorSensor() ); - registerVirtualSensor( new GravitySensor(list, count) ); - registerVirtualSensor( new LinearAccelerationSensor(list, count) ); + // Add Android virtual sensors if they're not already + // available in the HAL - // these are optional - registerVirtualSensor( new OrientationSensor() ); - registerVirtualSensor( new CorrectedGyroSensor(list, count) ); - } + aSensor = registerVirtualSensor( new RotationVectorSensor() ); + if (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR)) { + mUserSensorList.add(aSensor); + } - // build the sensor list returned to users - mUserSensorList = mSensorList; + aSensor = registerVirtualSensor( new GravitySensor(list, count) ); + if (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) { + mUserSensorList.add(aSensor); + } - if (hasGyro) { - // virtual debugging sensors are not added to mUserSensorList - registerVirtualSensor( new GyroDriftSensor() ); - } + aSensor = registerVirtualSensor( new LinearAccelerationSensor(list, count) ); + if (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) { + mUserSensorList.add(aSensor); + } - if (hasGyro && - (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR))) { - // if we have the fancy sensor fusion, and it's not provided by the - // HAL, use our own (fused) orientation sensor by removing the - // HAL supplied one form the user list. - if (orientationIndex >= 0) { - mUserSensorList.removeItemsAt(orientationIndex); + aSensor = registerVirtualSensor( new OrientationSensor() ); + if (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR)) { + // if we are doing our own rotation-vector, also add + // the orientation sensor and remove the HAL provided one. + mUserSensorList.replaceAt(aSensor, orientationIndex); } + + // virtual debugging sensors are not added to mUserSensorList + registerVirtualSensor( new CorrectedGyroSensor(list, count) ); + registerVirtualSensor( new GyroDriftSensor() ); } // debugging sensor list - for (size_t i=0 ; i<mSensorList.size() ; i++) { - switch (mSensorList[i].getType()) { - case SENSOR_TYPE_GRAVITY: - case SENSOR_TYPE_LINEAR_ACCELERATION: - case SENSOR_TYPE_ROTATION_VECTOR: - if (strstr(mSensorList[i].getVendor().string(), "Google")) { - mUserSensorListDebug.add(mSensorList[i]); - } - break; - default: - mUserSensorListDebug.add(mSensorList[i]); - break; - } - } + mUserSensorListDebug = mSensorList; run("SensorService", PRIORITY_URGENT_DISPLAY); mInitCheck = NO_ERROR; @@ -163,7 +154,7 @@ void SensorService::onFirstRef() } } -void SensorService::registerSensor(SensorInterface* s) +Sensor SensorService::registerSensor(SensorInterface* s) { sensors_event_t event; memset(&event, 0, sizeof(event)); @@ -175,12 +166,15 @@ void SensorService::registerSensor(SensorInterface* s) mSensorMap.add(sensor.getHandle(), s); // create an entry in the mLastEventSeen array mLastEventSeen.add(sensor.getHandle(), event); + + return sensor; } -void SensorService::registerVirtualSensor(SensorInterface* s) +Sensor SensorService::registerVirtualSensor(SensorInterface* s) { - registerSensor(s); + Sensor sensor = registerSensor(s); mVirtualSensorList.add( s ); + return sensor; } SensorService::~SensorService() diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 25e5f76..67489cc 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -50,12 +50,13 @@ class SensorService : public BnSensorServer, protected Thread { - friend class BinderService<SensorService>; + friend class BinderService<SensorService>; - static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz - static const char* WAKE_LOCK_NAME; + static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz + static const char* WAKE_LOCK_NAME; - SensorService(); + static char const* getServiceName() ANDROID_API { return "sensorservice"; } + SensorService() ANDROID_API; virtual ~SensorService(); virtual void onFirstRef(); @@ -113,12 +114,12 @@ class SensorService : int getSensorType(int handle) const; void recordLastValue(sensors_event_t const * buffer, size_t count); static void sortEventBuffer(sensors_event_t* buffer, size_t count); - void registerSensor(SensorInterface* sensor); - void registerVirtualSensor(SensorInterface* sensor); + Sensor registerSensor(SensorInterface* sensor); + Sensor registerVirtualSensor(SensorInterface* sensor); status_t cleanupWithoutDisable(const sp<SensorEventConnection>& connection, - int handle); + int handle); void cleanupAutoDisabledSensor(const sp<SensorEventConnection>& connection, - sensors_event_t const* buffer, const int count); + sensors_event_t const* buffer, const int count); // constants Vector<Sensor> mSensorList; @@ -138,8 +139,6 @@ class SensorService : KeyedVector<int32_t, sensors_event_t> mLastEventSeen; public: - static char const* getServiceName() { return "sensorservice"; } - void cleanupConnection(SensorEventConnection* connection); status_t enable(const sp<SensorEventConnection>& connection, int handle); status_t disable(const sp<SensorEventConnection>& connection, int handle); diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index ec296d3..f2051dd 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -18,6 +18,8 @@ LOCAL_SRC_FILES:= \ DisplayHardware/HWComposer.cpp \ DisplayHardware/PowerHAL.cpp \ DisplayHardware/VirtualDisplaySurface.cpp \ + EventLog/EventLogTags.logtags \ + EventLog/EventLog.cpp LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\" LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES @@ -41,6 +43,8 @@ ifneq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),) LOCAL_CFLAGS += -DNUM_FRAMEBUFFER_SURFACE_BUFFERS=$(NUM_FRAMEBUFFER_SURFACE_BUFFERS) endif +LOCAL_CFLAGS += -fvisibility=hidden + LOCAL_SHARED_LIBRARIES := \ libcutils \ liblog \ diff --git a/services/surfaceflinger/Colorizer.h b/services/surfaceflinger/Colorizer.h new file mode 100644 index 0000000..6524481 --- /dev/null +++ b/services/surfaceflinger/Colorizer.h @@ -0,0 +1,65 @@ +/* + * Copyright 2013 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. + */ + +#ifndef ANDROID_SURFACE_FLINGER_COLORIZER_H +#define ANDROID_SURFACE_FLINGER_COLORIZER_H + +namespace android { + +// --------------------------------------------------------------------------- + +class Colorizer { + bool mEnabled; +public: + enum color { + RED = 31, + GREEN = 32, + YELLOW = 33, + BLUE = 34, + MAGENTA = 35, + CYAN = 36, + WHITE = 37 + }; + + Colorizer(bool enabled) + : mEnabled(enabled) { + } + + void colorize(String8& out, color c) { + if (mEnabled) { + out.appendFormat("\e[%dm", c); + } + } + + void bold(String8& out) { + if (mEnabled) { + out.append("\e[1m"); + } + } + + void reset(String8& out) { + if (mEnabled) { + out.append("\e[0m"); + } + } +}; + +// --------------------------------------------------------------------------- + +}; // namespace android + + +#endif /* ANDROID_SURFACE_FLINGER_COLORIZER_H */ diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 68b0b7f..b001bdb 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -416,7 +416,7 @@ void DisplayDevice::setProjection(int orientation, mScissor = mGlobalTransform.transform(viewport); if (mScissor.isEmpty()) { - mScissor.set(getBounds()); + mScissor = getBounds(); } mOrientation = orientation; @@ -424,9 +424,9 @@ void DisplayDevice::setProjection(int orientation, mFrame = frame; } -void DisplayDevice::dump(String8& result, char* buffer, size_t SIZE) const { +void DisplayDevice::dump(String8& result) const { const Transform& tr(mGlobalTransform); - snprintf(buffer, SIZE, + result.appendFormat( "+ DisplayDevice: %s\n" " type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p, orient=%2d (type=%08x), " "flips=%u, isSecure=%d, secureVis=%d, acquired=%d, numLayers=%u\n" @@ -443,8 +443,6 @@ void DisplayDevice::dump(String8& result, char* buffer, size_t SIZE) const { tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]); - result.append(buffer); - String8 surfaceDump; mDisplaySurface->dump(surfaceDump); result.append(surfaceDump); diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 377d924..047eecd 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -153,7 +153,7 @@ public: * Debugging */ uint32_t getPageFlipCount() const; - void dump(String8& result, char* buffer, size_t SIZE) const; + void dump(String8& result) const; private: /* diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 54a3ce8..10bca38 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -103,8 +103,8 @@ status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && item.mBuf != mCurrentBufferSlot) { // Release the previous buffer. - err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY, - EGL_NO_SYNC_KHR); + err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err != NO_ERROR && err != BufferQueue::STALE_BUFFER_SLOT) { ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); return err; @@ -144,7 +144,8 @@ void FramebufferSurface::onFrameCommitted() { sp<Fence> fence = mHwc.getAndResetReleaseFence(mDisplayType); if (fence->isValid() && mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) { - status_t err = addReleaseFence(mCurrentBufferSlot, fence); + status_t err = addReleaseFence(mCurrentBufferSlot, + mCurrentBuffer, fence); ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)", strerror(-err), err); } @@ -175,11 +176,10 @@ void FramebufferSurface::dump(String8& result) const { ConsumerBase::dump(result); } -void FramebufferSurface::dumpLocked(String8& result, const char* prefix, - char* buffer, size_t SIZE) const +void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const { mHwc.fbDump(result); - ConsumerBase::dumpLocked(result, prefix, buffer, SIZE); + ConsumerBase::dumpLocked(result, prefix); } // ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index 2fde789..c86e9ae 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -55,8 +55,7 @@ private: virtual void onFrameAvailable(); virtual void freeBufferLocked(int slotIndex); - virtual void dumpLocked(String8& result, const char* prefix, - char* buffer, size_t SIZE) const; + virtual void dumpLocked(String8& result, const char* prefix) const; // nextBuffer waits for and then latches the next buffer from the // BufferQueue and releases the previously latched buffer to the diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index a9afbe5..5082192 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -550,9 +550,6 @@ status_t HWComposer::setFramebufferTarget(int32_t id, // triggers a Surface::queueBuffer() on some // devices (!?) -- log and ignore. ALOGE("HWComposer: framebufferTarget is null"); -// CallStack stack; -// stack.update(); -// stack.dump(""); return NO_ERROR; } @@ -962,7 +959,7 @@ HWComposer::LayerListIterator HWComposer::end(int32_t id) { return getLayerIterator(id, numLayers); } -void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const { +void HWComposer::dump(String8& result) const { if (mHwc) { result.appendFormat("Hardware Composer state (version %8x):\n", hwcApiVersion(mHwc)); result.appendFormat(" mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync); @@ -1030,6 +1027,8 @@ void HWComposer::dump(String8& result, char* buffer, size_t SIZE) const { } if (mHwc && mHwc->dump) { + const size_t SIZE = 4096; + char buffer[SIZE]; mHwc->dump(mHwc, buffer, SIZE); result.append(buffer); } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 604de38..a20da08 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -275,7 +275,7 @@ public: friend class VSyncThread; // for debugging ---------------------------------------------------------- - void dump(String8& out, char* scratch, size_t SIZE) const; + void dump(String8& out) const; private: void loadHwcModule(); diff --git a/services/surfaceflinger/EventLog/EventLog.cpp b/services/surfaceflinger/EventLog/EventLog.cpp new file mode 100644 index 0000000..815242b --- /dev/null +++ b/services/surfaceflinger/EventLog/EventLog.cpp @@ -0,0 +1,128 @@ +/* + * Copyright 2013 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 <stdio.h> +#include <stdlib.h> +#include <cutils/log.h> +#include <utils/String8.h> + +#include "EventLog.h" + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(EventLog) + + +EventLog::EventLog() { +} + +void EventLog::doLogJank(const String8& window, int32_t value) { + EventLog::TagBuffer buffer(LOGTAG_SF_JANK); + buffer.startList(2); + buffer.writeString8(window); + buffer.writeInt32(value); + buffer.endList(); + buffer.log(); +} + +void EventLog::logJank(const String8& window, int32_t value) { + EventLog::getInstance().doLogJank(window, value); +} + +// --------------------------------------------------------------------------- + +EventLog::TagBuffer::TagBuffer(int32_t tag) + : mPos(0), mTag(tag), mOverflow(false) { +} + +void EventLog::TagBuffer::log() { + if (mOverflow) { + ALOGW("couldn't log to binary event log: overflow."); + } else if (android_bWriteLog(mTag, mStorage, mPos) < 0) { + ALOGE("couldn't log to EventLog: %s", strerror(errno)); + } + // purge the buffer + mPos = 0; + mOverflow = false; +} + +void EventLog::TagBuffer::startList(int8_t count) { + if (mOverflow) return; + const size_t needed = 1 + sizeof(count); + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = EVENT_TYPE_LIST; + mStorage[mPos + 1] = count; + mPos += needed; +} + +void EventLog::TagBuffer::endList() { + if (mOverflow) return; + const size_t needed = 1; + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = '\n'; + mPos += needed; +} + +void EventLog::TagBuffer::writeInt32(int32_t value) { + if (mOverflow) return; + const size_t needed = 1 + sizeof(value); + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = EVENT_TYPE_INT; + memcpy(&mStorage[mPos + 1], &value, sizeof(value)); + mPos += needed; +} + +void EventLog::TagBuffer::writeInt64(int64_t value) { + if (mOverflow) return; + const size_t needed = 1 + sizeof(value); + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = EVENT_TYPE_LONG; + memcpy(&mStorage[mPos + 1], &value, sizeof(value)); + mPos += needed; +} + +void EventLog::TagBuffer::writeString8(const String8& value) { + if (mOverflow) return; + const int32_t stringLen = value.length(); + const size_t needed = 1 + sizeof(int32_t) + stringLen; + if (mPos + needed > STORAGE_MAX_SIZE) { + mOverflow = true; + return; + } + mStorage[mPos + 0] = EVENT_TYPE_STRING; + memcpy(&mStorage[mPos + 1], &stringLen, sizeof(int32_t)); + memcpy(&mStorage[mPos + 5], value.string(), stringLen); + mPos += needed; +} + +// --------------------------------------------------------------------------- +}// namespace android + +// --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/EventLog/EventLog.h b/services/surfaceflinger/EventLog/EventLog.h new file mode 100644 index 0000000..2f1cd9b --- /dev/null +++ b/services/surfaceflinger/EventLog/EventLog.h @@ -0,0 +1,83 @@ +/* + * Copyright 2013 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 <stdint.h> +#include <utils/Errors.h> +#include <utils/Singleton.h> + +#ifndef ANDROID_SF_EVENTLOG_H +#define ANDROID_SF_EVENTLOG_H + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +class String8; + +class EventLog : public Singleton<EventLog> { + +public: + static void logJank(const String8& window, int32_t value); + +protected: + EventLog(); + +private: + /* + * EventLogBuffer is a helper class to construct an in-memory event log + * tag. In this version the buffer is not dynamic, so write operation can + * fail if there is not enough space in the temporary buffer. + * Once constructed, the buffer can be logger by calling the log() + * method. + */ + + class TagBuffer { + enum { STORAGE_MAX_SIZE = 128 }; + int32_t mPos; + int32_t mTag; + bool mOverflow; + char mStorage[STORAGE_MAX_SIZE]; + public: + TagBuffer(int32_t tag); + + // starts list of items + void startList(int8_t count); + // terminates the list + void endList(); + // write a 32-bit integer + void writeInt32(int32_t value); + // write a 64-bit integer + void writeInt64(int64_t value); + // write a C string + void writeString8(const String8& value); + + // outputs the the buffer to the log + void log(); + }; + + friend class Singleton<EventLog>; + EventLog(const EventLog&); + EventLog& operator =(const EventLog&); + + enum { LOGTAG_SF_JANK = 60100 }; + void doLogJank(const String8& window, int32_t value); +}; + +// --------------------------------------------------------------------------- +}// namespace android +// --------------------------------------------------------------------------- + +#endif /* ANDROID_SF_EVENTLOG_H */ diff --git a/services/surfaceflinger/EventLog/EventLogTags.logtags b/services/surfaceflinger/EventLog/EventLogTags.logtags new file mode 100644 index 0000000..c83692f --- /dev/null +++ b/services/surfaceflinger/EventLog/EventLogTags.logtags @@ -0,0 +1,38 @@ +# The entries in this file map a sparse set of log tag numbers to tag names. +# This is installed on the device, in /system/etc, and parsed by logcat. +# +# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the +# negative values alone for now.) +# +# Tag names are one or more ASCII letters and numbers or underscores, i.e. +# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former +# impacts log readability, the latter makes regex searches more annoying). +# +# Tag numbers and names are separated by whitespace. Blank lines and lines +# starting with '#' are ignored. +# +# Optionally, after the tag names can be put a description for the value(s) +# of the tag. Description are in the format +# (<name>|data type[|data unit]) +# Multiple values are separated by commas. +# +# The data type is a number from the following values: +# 1: int +# 2: long +# 3: string +# 4: list +# +# The data unit is a number taken from the following list: +# 1: Number of objects +# 2: Number of bytes +# 3: Number of milliseconds +# 4: Number of allocations +# 5: Id +# 6: Percent +# Default value for data of type int/long is 2 (bytes). + +# surfaceflinger +60100 sf_jank (window|3),(value|1) + +# NOTE - the range 1000000-2000000 is reserved for partners and others who +# want to define their own log tags without conflicting with the core platform. diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index 4d0fc79..4126c8a 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -320,7 +320,7 @@ void EventThread::disableVSyncLocked() { mDebugVsyncEnabled = false; } -void EventThread::dump(String8& result, char* buffer, size_t SIZE) const { +void EventThread::dump(String8& result) const { Mutex::Autolock _l(mLock); result.appendFormat("VSYNC state: %s\n", mDebugVsyncEnabled?"enabled":"disabled"); diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h index 1934f98..f6bd676 100644 --- a/services/surfaceflinger/EventThread.h +++ b/services/surfaceflinger/EventThread.h @@ -84,7 +84,7 @@ public: Vector< sp<EventThread::Connection> > waitForEvent( DisplayEventReceiver::Event* event); - void dump(String8& result, char* buffer, size_t SIZE) const; + void dump(String8& result) const; private: virtual bool threadLoop(); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 4779804..b08b8d1 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -36,6 +36,7 @@ #include <gui/Surface.h> #include "clz.h" +#include "Colorizer.h" #include "DisplayDevice.h" #include "GLExtensions.h" #include "Layer.h" @@ -164,7 +165,7 @@ void Layer::onRemoved() { // set-up // --------------------------------------------------------------------------- -String8 Layer::getName() const { +const String8& Layer::getName() const { return mName; } @@ -269,13 +270,24 @@ uint32_t Layer::getContentTransform() const { return mCurrentTransform; } +static Rect reduce(const Rect& win, const Region& exclude) { + if (CC_LIKELY(exclude.isEmpty())) { + return win; + } + if (exclude.isRect()) { + return win.reduce(exclude.getBounds()); + } + return Region(win).subtract(exclude).getBounds(); +} + Rect Layer::computeBounds() const { - const Layer::State& s(drawingState()); + const Layer::State& s(getDrawingState()); Rect win(s.active.w, s.active.h); if (!s.active.crop.isEmpty()) { win.intersect(s.active.crop, &win); } - return win; + // subtract the transparent region and snap to the bounds + return reduce(win, s.activeTransparentRegion); } Rect Layer::computeCrop(const sp<const DisplayDevice>& hw) const { @@ -293,7 +305,7 @@ Rect Layer::computeCrop(const sp<const DisplayDevice>& hw) const { // the active.crop is the area of the window that gets cropped, but not // scaled in any ways. - const State& s(drawingState()); + const State& s(getDrawingState()); // apply the projection's clipping to the window crop in // layerstack space, and convert-back to layer space. @@ -309,6 +321,9 @@ Rect Layer::computeCrop(const sp<const DisplayDevice>& hw) const { // window's bounds activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop); + // subtract the transparent region and snap to the bounds + activeCrop = reduce(activeCrop, s.activeTransparentRegion); + if (!activeCrop.isEmpty()) { // Transform the window crop to match the buffer coordinate system, // which means using the inverse of the current transform set on the @@ -357,7 +372,7 @@ void Layer::setGeometry( } // this gives us only the "orientation" component of the transform - const State& s(drawingState()); + const State& s(getDrawingState()); if (!isOpaque() || s.alpha != 0xFF) { layer.setBlending(mPremultipliedAlpha ? HWC_BLENDING_PREMULT : @@ -544,31 +559,88 @@ void Layer::clearWithOpenGL( clearWithOpenGL(hw, clip, 0,0,0,0); } +static void setupOpenGL10(bool premultipliedAlpha, bool opaque, int alpha) { + // OpenGL ES 1.0 doesn't support texture combiners. + // This path doesn't properly handle opaque layers that have non-opaque + // alpha values. The alpha channel will be copied into the framebuffer or + // screenshot, so if the framebuffer or screenshot is blended on top of + // something else, whatever is below the window will incorrectly show + // through. + if (CC_UNLIKELY(alpha < 0xFF)) { + GLfloat floatAlpha = alpha * (1.0f / 255.0f); + if (premultipliedAlpha) { + glColor4f(floatAlpha, floatAlpha, floatAlpha, floatAlpha); + } else { + glColor4f(1.0f, 1.0f, 1.0f, floatAlpha); + } + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } else { + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } +} + +static void setupOpenGL11(bool premultipliedAlpha, bool opaque, int alpha) { + GLenum combineRGB; + GLenum combineAlpha; + GLenum src0Alpha; + GLfloat envColor[4]; + + if (CC_UNLIKELY(alpha < 0xFF)) { + // Cv = premultiplied ? Cs*alpha : Cs + // Av = !opaque ? alpha*As : 1.0 + combineRGB = premultipliedAlpha ? GL_MODULATE : GL_REPLACE; + combineAlpha = !opaque ? GL_MODULATE : GL_REPLACE; + src0Alpha = GL_CONSTANT; + envColor[0] = alpha * (1.0f / 255.0f); + } else { + // Cv = Cs + // Av = opaque ? 1.0 : As + combineRGB = GL_REPLACE; + combineAlpha = GL_REPLACE; + src0Alpha = opaque ? GL_CONSTANT : GL_TEXTURE; + envColor[0] = 1.0f; + } + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, combineRGB); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + if (combineRGB == GL_MODULATE) { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + } + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, combineAlpha); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, src0Alpha); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + if (combineAlpha == GL_MODULATE) { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); + } + if (combineRGB == GL_MODULATE || src0Alpha == GL_CONSTANT) { + envColor[1] = envColor[0]; + envColor[2] = envColor[0]; + envColor[3] = envColor[0]; + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor); + } +} + void Layer::drawWithOpenGL( const sp<const DisplayDevice>& hw, const Region& clip) const { const uint32_t fbHeight = hw->getHeight(); - const State& s(drawingState()); + const State& s(getDrawingState()); - GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA; - if (CC_UNLIKELY(s.alpha < 0xFF)) { - const GLfloat alpha = s.alpha * (1.0f/255.0f); - if (mPremultipliedAlpha) { - glColor4f(alpha, alpha, alpha, alpha); - } else { - glColor4f(1, 1, 1, alpha); - } + if (mFlinger->getGlesVersion() == GLES_VERSION_1_0) { + setupOpenGL10(mPremultipliedAlpha, isOpaque(), s.alpha); + } else { + setupOpenGL11(mPremultipliedAlpha, isOpaque(), s.alpha); + } + + if (s.alpha < 0xFF || !isOpaque()) { glEnable(GL_BLEND); - glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBlendFunc(mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA); } else { - glColor4f(1, 1, 1, 1); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - if (!isOpaque()) { - glEnable(GL_BLEND); - glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA); - } else { - glDisable(GL_BLEND); - } + glDisable(GL_BLEND); } LayerMesh mesh; @@ -658,13 +730,15 @@ bool Layer::getOpacityForFormat(uint32_t format) void Layer::computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh) const { - const Layer::State& s(drawingState()); + const Layer::State& s(getDrawingState()); const Transform tr(hw->getTransform() * s.transform); const uint32_t hw_h = hw->getHeight(); Rect win(s.active.w, s.active.h); if (!s.active.crop.isEmpty()) { win.intersect(s.active.crop, &win); } + // subtract the transparent region and snap to the bounds + win = reduce(win, s.activeTransparentRegion); if (mesh) { tr.transform(mesh->mVertices[0], win.left, win.top); tr.transform(mesh->mVertices[1], win.left, win.bottom); @@ -731,11 +805,11 @@ void Layer::setVisibleNonTransparentRegion(const Region& uint32_t Layer::doTransaction(uint32_t flags) { ATRACE_CALL(); - const Layer::State& front(drawingState()); - const Layer::State& temp(currentState()); + const Layer::State& s(getDrawingState()); + const Layer::State& c(getCurrentState()); - const bool sizeChanged = (temp.requested.w != front.requested.w) || - (temp.requested.h != front.requested.h); + const bool sizeChanged = (c.requested.w != s.requested.w) || + (c.requested.h != s.requested.h); if (sizeChanged) { // the size changed, we need to ask our client to request a new buffer @@ -745,46 +819,46 @@ uint32_t Layer::doTransaction(uint32_t flags) { " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n" " drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n" " requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n", - this, (const char*) getName(), mCurrentTransform, mCurrentScalingMode, - temp.active.w, temp.active.h, - temp.active.crop.left, - temp.active.crop.top, - temp.active.crop.right, - temp.active.crop.bottom, - temp.active.crop.getWidth(), - temp.active.crop.getHeight(), - temp.requested.w, temp.requested.h, - temp.requested.crop.left, - temp.requested.crop.top, - temp.requested.crop.right, - temp.requested.crop.bottom, - temp.requested.crop.getWidth(), - temp.requested.crop.getHeight(), - front.active.w, front.active.h, - front.active.crop.left, - front.active.crop.top, - front.active.crop.right, - front.active.crop.bottom, - front.active.crop.getWidth(), - front.active.crop.getHeight(), - front.requested.w, front.requested.h, - front.requested.crop.left, - front.requested.crop.top, - front.requested.crop.right, - front.requested.crop.bottom, - front.requested.crop.getWidth(), - front.requested.crop.getHeight()); + this, getName().string(), mCurrentTransform, mCurrentScalingMode, + c.active.w, c.active.h, + c.active.crop.left, + c.active.crop.top, + c.active.crop.right, + c.active.crop.bottom, + c.active.crop.getWidth(), + c.active.crop.getHeight(), + c.requested.w, c.requested.h, + c.requested.crop.left, + c.requested.crop.top, + c.requested.crop.right, + c.requested.crop.bottom, + c.requested.crop.getWidth(), + c.requested.crop.getHeight(), + s.active.w, s.active.h, + s.active.crop.left, + s.active.crop.top, + s.active.crop.right, + s.active.crop.bottom, + s.active.crop.getWidth(), + s.active.crop.getHeight(), + s.requested.w, s.requested.h, + s.requested.crop.left, + s.requested.crop.top, + s.requested.crop.right, + s.requested.crop.bottom, + s.requested.crop.getWidth(), + s.requested.crop.getHeight()); // record the new size, form this point on, when the client request // a buffer, it'll get the new size. mSurfaceFlingerConsumer->setDefaultBufferSize( - temp.requested.w, temp.requested.h); + c.requested.w, c.requested.h); } if (!isFixedSize()) { - const bool resizePending = (temp.requested.w != temp.active.w) || - (temp.requested.h != temp.active.h); + const bool resizePending = (c.requested.w != c.active.w) || + (c.requested.h != c.active.h); if (resizePending) { // don't let Layer::doTransaction update the drawing state @@ -804,23 +878,23 @@ uint32_t Layer::doTransaction(uint32_t flags) { // this is used by Layer, which special cases resizes. if (flags & eDontUpdateGeometryState) { } else { - Layer::State& editTemp(currentState()); - editTemp.active = temp.requested; + Layer::State& editCurrentState(getCurrentState()); + editCurrentState.active = c.requested; } - if (front.active != temp.active) { + if (s.active != c.active) { // invalidate and recompute the visible regions if needed flags |= Layer::eVisibleRegion; } - if (temp.sequence != front.sequence) { + if (c.sequence != s.sequence) { // invalidate and recompute the visible regions if needed flags |= eVisibleRegion; this->contentDirty = true; // we may use linear filtering, if the matrix scales us - const uint8_t type = temp.transform.getType(); - mNeedsFiltering = (!temp.transform.preserveRects() || + const uint8_t type = c.transform.getType(); + mNeedsFiltering = (!c.transform.preserveRects() || (type >= Transform::SCALE)); } @@ -1085,7 +1159,7 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) }; - Reject r(mDrawingState, currentState(), recomputeVisibleRegions); + Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions); if (mSurfaceFlingerConsumer->updateTexImage(&r) != NO_ERROR) { // something happened! @@ -1139,11 +1213,11 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // FIXME: postedRegion should be dirty & bounds - const Layer::State& front(drawingState()); - Region dirtyRegion(Rect(front.active.w, front.active.h)); + const Layer::State& s(getDrawingState()); + Region dirtyRegion(Rect(s.active.w, s.active.h)); // transform the dirty region to window-manager space - outDirtyRegion = (front.transform.transform(dirtyRegion)); + outDirtyRegion = (s.transform.transform(dirtyRegion)); } return outDirtyRegion; } @@ -1178,21 +1252,21 @@ void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const { // debugging // ---------------------------------------------------------------------------- -void Layer::dump(String8& result, char* buffer, size_t SIZE) const +void Layer::dump(String8& result, Colorizer& colorizer) const { - const Layer::State& s(drawingState()); + const Layer::State& s(getDrawingState()); - snprintf(buffer, SIZE, + colorizer.colorize(result, Colorizer::GREEN); + result.appendFormat( "+ %s %p (%s)\n", getTypeId(), this, getName().string()); - result.append(buffer); + colorizer.reset(result); s.activeTransparentRegion.dump(result, "transparentRegion"); visibleRegion.dump(result, "visibleRegion"); sp<Client> client(mClientRef.promote()); - snprintf(buffer, SIZE, - " " + result.appendFormat( " " "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), " "isOpaque=%1d, invalidate=%1d, " "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" @@ -1205,7 +1279,6 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const s.transform[0][0], s.transform[0][1], s.transform[1][0], s.transform[1][1], client.get()); - result.append(buffer); sp<const GraphicBuffer> buf0(mActiveBuffer); uint32_t w0=0, h0=0, s0=0, f0=0; @@ -1215,26 +1288,19 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const s0 = buf0->getStride(); f0 = buf0->format; } - snprintf(buffer, SIZE, + result.appendFormat( " " "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X]," " queued-frames=%d, mRefreshPending=%d\n", mFormat, w0, h0, s0,f0, mQueuedFrames, mRefreshPending); - result.append(buffer); - if (mSurfaceFlingerConsumer != 0) { - mSurfaceFlingerConsumer->dump(result, " ", buffer, SIZE); + mSurfaceFlingerConsumer->dump(result, " "); } } - -void Layer::shortDump(String8& result, char* scratch, size_t size) const { - Layer::dump(result, scratch, size); -} - -void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const { +void Layer::dumpStats(String8& result) const { mFrameTracker.dump(result); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 2765db1..f79bf2d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -51,6 +51,7 @@ namespace android { // --------------------------------------------------------------------------- class Client; +class Colorizer; class DisplayDevice; class GraphicBuffer; class SurfaceFlinger; @@ -130,6 +131,7 @@ public: Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w, uint32_t h, uint32_t flags); + virtual ~Layer(); // the this layer's size and format @@ -146,8 +148,6 @@ public: bool setCrop(const Rect& crop); bool setLayerStack(uint32_t layerStack); - void commitTransaction(); - uint32_t getTransactionFlags(uint32_t flags); uint32_t setTransactionFlags(uint32_t flags); @@ -156,79 +156,104 @@ public: sp<IBinder> getHandle(); sp<BufferQueue> getBufferQueue() const; - String8 getName() const; + const String8& getName() const; // ----------------------------------------------------------------------- + // Virtuals virtual const char* getTypeId() const { return "Layer"; } - virtual void setGeometry(const sp<const DisplayDevice>& hw, + /* + * isOpaque - true if this surface is opaque + */ + virtual bool isOpaque() const; + + /* + * isSecure - true if this surface is secure, that is if it prevents + * screenshots or VNC servers. + */ + virtual bool isSecure() const { return mSecure; } + + /* + * isProtected - true if the layer may contain protected content in the + * GRALLOC_USAGE_PROTECTED sense. + */ + virtual bool isProtected() const; + + /* + * isVisible - true if this layer is visible, false otherwise + */ + virtual bool isVisible() const; + + /* + * isFixedSize - true if content has a fixed size + */ + virtual bool isFixedSize() const; + +protected: + /* + * onDraw - draws the surface. + */ + virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const; + +public: + // ----------------------------------------------------------------------- + + void setGeometry(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer); - virtual void setPerFrameData(const sp<const DisplayDevice>& hw, + void setPerFrameData(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer); - virtual void setAcquireFence(const sp<const DisplayDevice>& hw, + void setAcquireFence(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface& layer); /* * called after page-flip */ - virtual void onLayerDisplayed(const sp<const DisplayDevice>& hw, + void onLayerDisplayed(const sp<const DisplayDevice>& hw, HWComposer::HWCLayerInterface* layer); /* * called before composition. * returns true if the layer has pending updates. */ - virtual bool onPreComposition(); + bool onPreComposition(); /* * called after composition. */ - virtual void onPostComposition(); + void onPostComposition(); /* * draw - performs some global clipping optimizations * and calls onDraw(). - * Typically this method is not overridden, instead implement onDraw() - * to perform the actual drawing. - */ - virtual void draw(const sp<const DisplayDevice>& hw, const Region& clip) const; - virtual void draw(const sp<const DisplayDevice>& hw); - - /* - * onDraw - draws the surface. */ - virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const; - - /* - * needsLinearFiltering - true if this surface's state requires filtering - */ - virtual bool needsFiltering(const sp<const DisplayDevice>& hw) const; + void draw(const sp<const DisplayDevice>& hw, const Region& clip) const; + void draw(const sp<const DisplayDevice>& hw); /* * doTransaction - process the transaction. This is a good place to figure * out which attributes of the surface have changed. */ - virtual uint32_t doTransaction(uint32_t transactionFlags); + uint32_t doTransaction(uint32_t transactionFlags); /* * setVisibleRegion - called to set the new visible region. This gives * a chance to update the new visible region or record the fact it changed. */ - virtual void setVisibleRegion(const Region& visibleRegion); + void setVisibleRegion(const Region& visibleRegion); /* * setCoveredRegion - called when the covered region changes. The covered * region corresponds to any area of the surface that is covered * (transparently or not) by another surface. */ - virtual void setCoveredRegion(const Region& coveredRegion); + void setCoveredRegion(const Region& coveredRegion); /* * setVisibleNonTransparentRegion - called when the visible and * non-transparent region changes. */ - virtual void setVisibleNonTransparentRegion(const Region& + void setVisibleNonTransparentRegion(const Region& visibleNonTransparentRegion); /* @@ -237,57 +262,30 @@ public: * operation, so this should be set only if needed). Typically this is used * to figure out if the content or size of a surface has changed. */ - virtual Region latchBuffer(bool& recomputeVisibleRegions); - - /* - * isOpaque - true if this surface is opaque - */ - virtual bool isOpaque() const; - - /* - * isSecure - true if this surface is secure, that is if it prevents - * screenshots or VNC servers. - */ - virtual bool isSecure() const { return mSecure; } - - /* - * isProtected - true if the layer may contain protected content in the - * GRALLOC_USAGE_PROTECTED sense. - */ - virtual bool isProtected() const; - - /* - * isVisible - true if this layer is visible, false otherwise - */ - virtual bool isVisible() const; - - /* - * isFixedSize - true if content has a fixed size - */ - virtual bool isFixedSize() const; + Region latchBuffer(bool& recomputeVisibleRegions); /* * called with the state lock when the surface is removed from the * current list */ - virtual void onRemoved(); + void onRemoved(); // Updates the transform hint in our SurfaceFlingerConsumer to match // the current orientation of the display device. - virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const; + void updateTransformHint(const sp<const DisplayDevice>& hw) const; /* * returns the rectangle that crops the content of the layer and scales it * to the layer's size. */ - virtual Rect getContentCrop() const; + Rect getContentCrop() const; /* * returns the transform bits (90 rotation / h-flip / v-flip) of the * layer's content */ - virtual uint32_t getContentTransform() const; + uint32_t getContentTransform() const; // ----------------------------------------------------------------------- @@ -298,16 +296,15 @@ public: // only for debugging inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; } - inline const State& drawingState() const { return mDrawingState; } - inline const State& currentState() const { return mCurrentState; } - inline State& currentState() { return mCurrentState; } + inline const State& getDrawingState() const { return mDrawingState; } + inline const State& getCurrentState() const { return mCurrentState; } + inline State& getCurrentState() { return mCurrentState; } /* always call base class first */ - virtual void dump(String8& result, char* scratch, size_t size) const; - virtual void shortDump(String8& result, char* scratch, size_t size) const; - virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const; - virtual void clearStats(); + void dump(String8& result, Colorizer& colorizer) const; + void dumpStats(String8& result) const; + void clearStats(); protected: // constant @@ -333,6 +330,10 @@ private: // Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener virtual void onFrameAvailable(); + void commitTransaction(); + + // needsLinearFiltering - true if this surface's state requires filtering + bool needsFiltering(const sp<const DisplayDevice>& hw) const; uint32_t getEffectiveUsage(uint32_t usage) const; Rect computeCrop(const sp<const DisplayDevice>& hw) const; diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp index 36bafdb..f4adeeb 100644 --- a/services/surfaceflinger/LayerDim.cpp +++ b/services/surfaceflinger/LayerDim.cpp @@ -43,7 +43,7 @@ LayerDim::~LayerDim() { void LayerDim::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const { - const State& s(drawingState()); + const State& s(getDrawingState()); if (s.alpha>0) { const GLfloat alpha = s.alpha/255.0f; const uint32_t fbHeight = hw->getHeight(); @@ -71,7 +71,7 @@ void LayerDim::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) con } bool LayerDim::isVisible() const { - const Layer::State& s(drawingState()); + const Layer::State& s(getDrawingState()); return !(s.flags & layer_state_t::eLayerHidden) && s.alpha; } diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h index e19bf52..2a96149 100644 --- a/services/surfaceflinger/LayerDim.h +++ b/services/surfaceflinger/LayerDim.h @@ -36,13 +36,10 @@ public: const String8& name, uint32_t w, uint32_t h, uint32_t flags); virtual ~LayerDim(); + virtual const char* getTypeId() const { return "LayerDim"; } virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const; virtual bool isOpaque() const { return false; } virtual bool isSecure() const { return false; } - virtual bool isProtectedByApp() const { return false; } - virtual bool isProtectedByDRM() const { return false; } - virtual const char* getTypeId() const { return "LayerDim"; } - virtual bool isFixedSize() const { return true; } virtual bool isVisible() const; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ef0d521..fc193e5 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -55,10 +55,11 @@ #include <private/android_filesystem_config.h> #include <private/gui/SyncFeatures.h> +#include "Client.h" #include "clz.h" +#include "Colorizer.h" #include "DdmConnection.h" #include "DisplayDevice.h" -#include "Client.h" #include "EventThread.h" #include "GLExtensions.h" #include "Layer.h" @@ -413,6 +414,22 @@ EGLContext SurfaceFlinger::createGLContext(EGLDisplay display, EGLConfig config) return ctxt; } +static GlesVersion parseGlesVersion(const char* str) { + int major, minor; + if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) { + ALOGW("Unable to parse GL_VERSION string: \"%s\"", str); + return GLES_VERSION_1_0; + } + + if (major == 1 && minor == 0) return GLES_VERSION_1_0; + if (major == 1 && minor >= 1) return GLES_VERSION_1_1; + if (major == 2 && minor >= 0) return GLES_VERSION_2_0; + if (major == 3 && minor >= 0) return GLES_VERSION_3_0; + + ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor); + return GLES_VERSION_1_0; +} + void SurfaceFlinger::initializeGL(EGLDisplay display) { GLExtensions& extensions(GLExtensions::getInstance()); extensions.initWithGLStrings( @@ -424,6 +441,8 @@ void SurfaceFlinger::initializeGL(EGLDisplay display) { eglQueryString(display, EGL_VERSION), eglQueryString(display, EGL_EXTENSIONS)); + mGlesVersion = parseGlesVersion(extensions.getVersion()); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); @@ -837,10 +856,10 @@ void SurfaceFlinger::doDebugFlashRegions() void SurfaceFlinger::preComposition() { bool needExtraInvalidate = false; - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - const size_t count = currentLayers.size(); + const LayerVector& layers(mDrawingState.layersSortedByZ); + const size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { - if (currentLayers[i]->onPreComposition()) { + if (layers[i]->onPreComposition()) { needExtraInvalidate = true; } } @@ -851,10 +870,10 @@ void SurfaceFlinger::preComposition() void SurfaceFlinger::postComposition() { - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - const size_t count = currentLayers.size(); + const LayerVector& layers(mDrawingState.layersSortedByZ); + const size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { - currentLayers[i]->onPostComposition(); + layers[i]->onPostComposition(); } if (mAnimCompositionPending) { @@ -881,7 +900,7 @@ void SurfaceFlinger::rebuildLayerStacks() { mVisibleRegionsDirty = false; invalidateHwcGeometry(); - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); + const LayerVector& layers(mDrawingState.layersSortedByZ); for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { Region opaqueRegion; Region dirtyRegion; @@ -890,13 +909,13 @@ void SurfaceFlinger::rebuildLayerStacks() { const Transform& tr(hw->getTransform()); const Rect bounds(hw->getBounds()); if (hw->canDraw()) { - SurfaceFlinger::computeVisibleRegions(currentLayers, + SurfaceFlinger::computeVisibleRegions(layers, hw->getLayerStack(), dirtyRegion, opaqueRegion); - const size_t count = currentLayers.size(); + const size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { - const sp<Layer>& layer(currentLayers[i]); - const Layer::State& s(layer->drawingState()); + const sp<Layer>& layer(layers[i]); + const Layer::State& s(layer->getDrawingState()); if (s.layerStack == hw->getLayerStack()) { Region drawRegion(tr.transform( layer->visibleNonTransparentRegion)); @@ -1037,6 +1056,12 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { ATRACE_CALL(); + // here we keep a copy of the drawing state (that is the state that's + // going to be overwritten by handleTransactionLocked()) outside of + // mStateLock so that the side-effects of the State assignment + // don't happen with mStateLock held (which can cause deadlocks). + State drawingState(mDrawingState); + Mutex::Autolock _l(mStateLock); const nsecs_t now = systemTime(); mDebugInTransaction = now; @@ -1232,7 +1257,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // layerStack first (so we don't have to traverse the list // of displays for every layer). const sp<Layer>& layer(currentLayers[i]); - uint32_t layerStack = layer->drawingState().layerStack; + uint32_t layerStack = layer->getDrawingState().layerStack; if (i==0 || currentlayerStack != layerStack) { currentlayerStack = layerStack; // figure out if this layerstack is mirrored @@ -1269,8 +1294,8 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) * Perform our own transaction if needed */ - const LayerVector& previousLayers(mDrawingState.layersSortedByZ); - if (currentLayers.size() > previousLayers.size()) { + const LayerVector& layers(mDrawingState.layersSortedByZ); + if (currentLayers.size() > layers.size()) { // layers have been added mVisibleRegionsDirty = true; } @@ -1280,15 +1305,15 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (mLayersRemoved) { mLayersRemoved = false; mVisibleRegionsDirty = true; - const size_t count = previousLayers.size(); + const size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { - const sp<Layer>& layer(previousLayers[i]); + const sp<Layer>& layer(layers[i]); if (currentLayers.indexOf(layer) < 0) { // this layer is not visible anymore // TODO: we could traverse the tree from front to back and // compute the actual visible region // TODO: we could cache the transformed region - const Layer::State& s(layer->drawingState()); + const Layer::State& s(layer->getDrawingState()); Region visibleReg = s.transform.transform( Region(Rect(s.active.w, s.active.h))); invalidateLayerStack(s.layerStack, visibleReg); @@ -1336,7 +1361,7 @@ void SurfaceFlinger::computeVisibleRegions( const sp<Layer>& layer = currentLayers[i]; // start with the whole surface at its current location - const Layer::State& s(layer->drawingState()); + const Layer::State& s(layer->getDrawingState()); // only consider the layers on the given layer stack if (s.layerStack != layerStack) @@ -1473,12 +1498,12 @@ void SurfaceFlinger::handlePageFlip() Region dirtyRegion; bool visibleRegions = false; - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - const size_t count = currentLayers.size(); + const LayerVector& layers(mDrawingState.layersSortedByZ); + const size_t count = layers.size(); for (size_t i=0 ; i<count ; i++) { - const sp<Layer>& layer(currentLayers[i]); + const sp<Layer>& layer(layers[i]); const Region dirty(layer->latchBuffer(visibleRegions)); - const Layer::State& s(layer->drawingState()); + const Layer::State& s(layer->getDrawingState()); invalidateLayerStack(s.layerStack, dirty); } @@ -2145,19 +2170,15 @@ void SurfaceFlinger::blank(const sp<IBinder>& display) { status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) { - const size_t SIZE = 4096; - char buffer[SIZE]; String8 result; - IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { - snprintf(buffer, SIZE, "Permission Denial: " + result.appendFormat("Permission Denial: " "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); - result.append(buffer); } else { // Try to get the main lock, but don't insist if we can't // (this would indicate SF is stuck, but we want to be able to @@ -2168,10 +2189,9 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) } const bool locked(retry >= 0); if (!locked) { - snprintf(buffer, SIZE, + result.append( "SurfaceFlinger appears to be unresponsive, " "dumping anyways (no locks held)\n"); - result.append(buffer); } bool dumpAll = true; @@ -2181,27 +2201,27 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) if ((index < numArgs) && (args[index] == String16("--list"))) { index++; - listLayersLocked(args, index, result, buffer, SIZE); + listLayersLocked(args, index, result); dumpAll = false; } if ((index < numArgs) && (args[index] == String16("--latency"))) { index++; - dumpStatsLocked(args, index, result, buffer, SIZE); + dumpStatsLocked(args, index, result); dumpAll = false; } if ((index < numArgs) && (args[index] == String16("--latency-clear"))) { index++; - clearStatsLocked(args, index, result, buffer, SIZE); + clearStatsLocked(args, index, result); dumpAll = false; } } if (dumpAll) { - dumpAllLocked(result, buffer, SIZE); + dumpAllLocked(args, index, result); } if (locked) { @@ -2213,19 +2233,18 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) } void SurfaceFlinger::listLayersLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const + String8& result) const { const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); for (size_t i=0 ; i<count ; i++) { const sp<Layer>& layer(currentLayers[i]); - snprintf(buffer, SIZE, "%s\n", layer->getName().string()); - result.append(buffer); + result.appendFormat("%s\n", layer->getName().string()); } } void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const + String8& result) const { String8 name; if (index < args.size()) { @@ -2245,14 +2264,14 @@ void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index for (size_t i=0 ; i<count ; i++) { const sp<Layer>& layer(currentLayers[i]); if (name == layer->getName()) { - layer->dumpStats(result, buffer, SIZE); + layer->dumpStats(result); } } } } void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) + String8& result) { String8 name; if (index < args.size()) { @@ -2292,9 +2311,18 @@ void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& inde result.append(config); } -void SurfaceFlinger::dumpAllLocked( - String8& result, char* buffer, size_t SIZE) const +void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, + String8& result) const { + bool colorize = false; + if (index < args.size() + && (args[index] == String16("--color"))) { + colorize = true; + index++; + } + + Colorizer colorizer(colorize); + // figure out if we're stuck somewhere const nsecs_t now = systemTime(); const nsecs_t inSwapBuffers(mDebugInSwapBuffers); @@ -2305,13 +2333,18 @@ void SurfaceFlinger::dumpAllLocked( /* * Dump library configuration. */ + + colorizer.bold(result); result.append("Build configuration:"); + colorizer.reset(result); appendSfConfigString(result); appendUiConfigString(result); appendGuiConfigString(result); result.append("\n"); + colorizer.bold(result); result.append("Sync configuration: "); + colorizer.reset(result); result.append(SyncFeatures::getInstance().toString()); result.append("\n"); @@ -2320,56 +2353,57 @@ void SurfaceFlinger::dumpAllLocked( */ const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); - snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count); - result.append(buffer); + colorizer.bold(result); + result.appendFormat("Visible layers (count = %d)\n", count); + colorizer.reset(result); for (size_t i=0 ; i<count ; i++) { const sp<Layer>& layer(currentLayers[i]); - layer->dump(result, buffer, SIZE); + layer->dump(result, colorizer); } /* * Dump Display state */ - snprintf(buffer, SIZE, "Displays (%d entries)\n", mDisplays.size()); - result.append(buffer); + colorizer.bold(result); + result.appendFormat("Displays (%d entries)\n", mDisplays.size()); + colorizer.reset(result); for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { const sp<const DisplayDevice>& hw(mDisplays[dpy]); - hw->dump(result, buffer, SIZE); + hw->dump(result); } /* * Dump SurfaceFlinger global state */ - snprintf(buffer, SIZE, "SurfaceFlinger global state:\n"); - result.append(buffer); + colorizer.bold(result); + result.append("SurfaceFlinger global state:\n"); + colorizer.reset(result); HWComposer& hwc(getHwComposer()); sp<const DisplayDevice> hw(getDefaultDisplayDevice()); const GLExtensions& extensions(GLExtensions::getInstance()); - snprintf(buffer, SIZE, "EGL implementation : %s\n", + colorizer.bold(result); + result.appendFormat("EGL implementation : %s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION)); - result.append(buffer); - snprintf(buffer, SIZE, "%s\n", + colorizer.reset(result); + result.appendFormat("%s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS)); - result.append(buffer); - snprintf(buffer, SIZE, "GLES: %s, %s, %s\n", + colorizer.bold(result); + result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(), extensions.getVersion()); - result.append(buffer); - snprintf(buffer, SIZE, "%s\n", extensions.getExtension()); - result.append(buffer); + colorizer.reset(result); + result.appendFormat("%s\n", extensions.getExtension()); hw->undefinedRegion.dump(result, "undefinedRegion"); - snprintf(buffer, SIZE, - " orientation=%d, canDraw=%d\n", + result.appendFormat(" orientation=%d, canDraw=%d\n", hw->getOrientation(), hw->canDraw()); - result.append(buffer); - snprintf(buffer, SIZE, + result.appendFormat( " last eglSwapBuffers() time: %f us\n" " last transaction time : %f us\n" " transaction-flags : %08x\n" @@ -2387,31 +2421,28 @@ void SurfaceFlinger::dumpAllLocked( hwc.getDpiY(HWC_DISPLAY_PRIMARY), mEGLNativeVisualId, !mGpuToCpuSupported); - result.append(buffer); - snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n", + result.appendFormat(" eglSwapBuffers time: %f us\n", inSwapBuffersDuration/1000.0); - result.append(buffer); - snprintf(buffer, SIZE, " transaction time: %f us\n", + result.appendFormat(" transaction time: %f us\n", inTransactionDuration/1000.0); - result.append(buffer); /* * VSYNC state */ - mEventThread->dump(result, buffer, SIZE); + mEventThread->dump(result); /* * Dump HWComposer state */ - snprintf(buffer, SIZE, "h/w composer state:\n"); - result.append(buffer); - snprintf(buffer, SIZE, " h/w composer %s and %s\n", + colorizer.bold(result); + result.append("h/w composer state:\n"); + colorizer.reset(result); + result.appendFormat(" h/w composer %s and %s\n", hwc.initCheck()==NO_ERROR ? "present" : "not present", (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled"); - result.append(buffer); - hwc.dump(result, buffer, SIZE); + hwc.dump(result); /* * Dump gralloc state @@ -2571,86 +2602,6 @@ void SurfaceFlinger::repaintEverything() { // Capture screen into an IGraphiBufferProducer // --------------------------------------------------------------------------- -/* The code below is here to handle b/8734824 - * - * We create a IGraphicBufferProducer wrapper that forwards all calls - * to the calling binder thread, where they are executed. This allows - * the calling thread to be reused (on the other side) and not - * depend on having "enough" binder threads to handle the requests. - * - */ - -class GraphicProducerWrapper : public BBinder, public MessageHandler { - sp<IGraphicBufferProducer> impl; - sp<Looper> looper; - status_t result; - bool exitPending; - bool exitRequested; - mutable Barrier barrier; - volatile int32_t memoryBarrier; - uint32_t code; - Parcel const* data; - Parcel* reply; - - enum { - MSG_API_CALL, - MSG_EXIT - }; - - /* - * this is called by our "fake" BpGraphicBufferProducer. We package the - * data and reply Parcel and forward them to the calling thread. - */ - virtual status_t transact(uint32_t code, - const Parcel& data, Parcel* reply, uint32_t flags) { - this->code = code; - this->data = &data; - this->reply = reply; - android_atomic_acquire_store(0, &memoryBarrier); - if (exitPending) { - // if we've exited, we run the message synchronously right here - handleMessage(Message(MSG_API_CALL)); - } else { - barrier.close(); - looper->sendMessage(this, Message(MSG_API_CALL)); - barrier.wait(); - } - return NO_ERROR; - } - - /* - * here we run on the binder calling thread. All we've got to do is - * call the real BpGraphicBufferProducer. - */ - virtual void handleMessage(const Message& message) { - android_atomic_release_load(&memoryBarrier); - if (message.what == MSG_API_CALL) { - impl->asBinder()->transact(code, data[0], reply); - barrier.open(); - } else if (message.what == MSG_EXIT) { - exitRequested = true; - } - } - -public: - GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl) : - impl(impl), looper(new Looper(true)), result(NO_ERROR), - exitPending(false), exitRequested(false) { - } - - status_t waitForResponse() { - do { - looper->pollOnce(-1); - } while (!exitRequested); - return result; - } - - void exit(status_t result) { - exitPending = true; - looper->sendMessage(this, Message(MSG_EXIT)); - } -}; - status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, const sp<IGraphicBufferProducer>& producer, uint32_t reqWidth, uint32_t reqHeight, @@ -2663,25 +2614,24 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, if (CC_UNLIKELY(producer == 0)) return BAD_VALUE; - class MessageCaptureScreen : public MessageBase { SurfaceFlinger* flinger; sp<IBinder> display; sp<IGraphicBufferProducer> producer; uint32_t reqWidth, reqHeight; uint32_t minLayerZ,maxLayerZ; - bool useReadPixels; + bool isCpuConsumer; status_t result; public: MessageCaptureScreen(SurfaceFlinger* flinger, const sp<IBinder>& display, const sp<IGraphicBufferProducer>& producer, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ, bool useReadPixels) + uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer) : flinger(flinger), display(display), producer(producer), reqWidth(reqWidth), reqHeight(reqHeight), minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), - useReadPixels(useReadPixels), + isCpuConsumer(isCpuConsumer), result(PERMISSION_DENIED) { } @@ -2691,14 +2641,11 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, virtual bool handler() { Mutex::Autolock _l(flinger->mStateLock); sp<const DisplayDevice> hw(flinger->getDisplayDevice(display)); - if (!useReadPixels) { - result = flinger->captureScreenImplLocked(hw, - producer, reqWidth, reqHeight, minLayerZ, maxLayerZ); - } else { - result = flinger->captureScreenImplCpuConsumerLocked(hw, - producer, reqWidth, reqHeight, minLayerZ, maxLayerZ); - } - static_cast<GraphicProducerWrapper*>(producer->asBinder().get())->exit(result); + bool useReadPixels = isCpuConsumer && !flinger->mGpuToCpuSupported; + result = flinger->captureScreenImplLocked(hw, + producer, reqWidth, reqHeight, minLayerZ, maxLayerZ, + useReadPixels); + return true; } }; @@ -2710,40 +2657,12 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, // scheduled at this time, this will end-up being a no-op as well. mEventQueue.invalidateTransactionNow(); - bool useReadPixels = false; - if (isCpuConsumer) { - bool formatSupportedBytBitmap = - (mEGLNativeVisualId == HAL_PIXEL_FORMAT_RGBA_8888) || - (mEGLNativeVisualId == HAL_PIXEL_FORMAT_RGBX_8888); - if (formatSupportedBytBitmap == false) { - // the pixel format we have is not compatible with - // Bitmap.java, which is the likely client of this API, - // so we just revert to glReadPixels() in that case. - useReadPixels = true; - } - if (mGpuToCpuSupported == false) { - // When we know the GL->CPU path works, we can call - // captureScreenImplLocked() directly, instead of using the - // glReadPixels() workaround. - useReadPixels = true; - } - } - - // this creates a "fake" BBinder which will serve as a "fake" remote - // binder to receive the marshaled calls and forward them to the - // real remote (a BpGraphicBufferProducer) - sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer); - - // the asInterface() call below creates our "fake" BpGraphicBufferProducer - // which does the marshaling work forwards to our "fake remote" above. sp<MessageBase> msg = new MessageCaptureScreen(this, - display, IGraphicBufferProducer::asInterface( wrapper ), - reqWidth, reqHeight, minLayerZ, maxLayerZ, - useReadPixels); - - status_t res = postMessageAsync(msg); + display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ, + isCpuConsumer); + status_t res = postMessageSync(msg); if (res == NO_ERROR) { - res = wrapper->waitForResponse(); + res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult(); } return res; } @@ -2786,7 +2705,7 @@ void SurfaceFlinger::renderScreenImplLocked( const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { const sp<Layer>& layer(layers[i]); - const Layer::State& state(layer->drawingState()); + const Layer::State& state(layer->getDrawingState()); if (state.layerStack == hw->getLayerStack()) { if (state.z >= minLayerZ && state.z <= maxLayerZ) { if (layer->isVisible()) { @@ -2807,73 +2726,8 @@ status_t SurfaceFlinger::captureScreenImplLocked( const sp<const DisplayDevice>& hw, const sp<IGraphicBufferProducer>& producer, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) -{ - ATRACE_CALL(); - - // get screen geometry - const uint32_t hw_w = hw->getWidth(); - const uint32_t hw_h = hw->getHeight(); - - // if we have secure windows on this display, never allow the screen capture - if (hw->getSecureLayerVisible()) { - ALOGW("FB is protected: PERMISSION_DENIED"); - return PERMISSION_DENIED; - } - - if ((reqWidth > hw_w) || (reqHeight > hw_h)) { - ALOGE("size mismatch (%d, %d) > (%d, %d)", - reqWidth, reqHeight, hw_w, hw_h); - return BAD_VALUE; - } - - reqWidth = (!reqWidth) ? hw_w : reqWidth; - reqHeight = (!reqHeight) ? hw_h : reqHeight; - - // Create a surface to render into - sp<Surface> surface = new Surface(producer); - ANativeWindow* const window = surface.get(); - - // set the buffer size to what the user requested - native_window_set_buffers_user_dimensions(window, reqWidth, reqHeight); - - // and create the corresponding EGLSurface - EGLSurface eglSurface = eglCreateWindowSurface( - mEGLDisplay, mEGLConfig, window, NULL); - if (eglSurface == EGL_NO_SURFACE) { - ALOGE("captureScreenImplLocked: eglCreateWindowSurface() failed 0x%4x", - eglGetError()); - return BAD_VALUE; - } - - if (!eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext)) { - ALOGE("captureScreenImplLocked: eglMakeCurrent() failed 0x%4x", - eglGetError()); - eglDestroySurface(mEGLDisplay, eglSurface); - return BAD_VALUE; - } - - renderScreenImplLocked(hw, reqWidth, reqHeight, minLayerZ, maxLayerZ, false); - - // and finishing things up... - if (eglSwapBuffers(mEGLDisplay, eglSurface) != EGL_TRUE) { - ALOGE("captureScreenImplLocked: eglSwapBuffers() failed 0x%4x", - eglGetError()); - eglDestroySurface(mEGLDisplay, eglSurface); - return BAD_VALUE; - } - - eglDestroySurface(mEGLDisplay, eglSurface); - - return NO_ERROR; -} - - -status_t SurfaceFlinger::captureScreenImplCpuConsumerLocked( - const sp<const DisplayDevice>& hw, - const sp<IGraphicBufferProducer>& producer, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useReadPixels) { ATRACE_CALL(); @@ -2900,67 +2754,103 @@ status_t SurfaceFlinger::captureScreenImplCpuConsumerLocked( reqWidth = (!reqWidth) ? hw_w : reqWidth; reqHeight = (!reqHeight) ? hw_h : reqHeight; - GLuint tname; - glGenRenderbuffersOES(1, &tname); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, reqWidth, reqHeight); + // create a surface (because we're a producer, and we need to + // dequeue/queue a buffer) + sp<Surface> sur = new Surface(producer); + ANativeWindow* window = sur.get(); - // create a FBO - GLuint name; - glGenFramebuffersOES(1, &name); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, - GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); + status_t result = NO_ERROR; + if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) == NO_ERROR) { + uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; + if (!useReadPixels) { + usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; + } - GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + int err = 0; + err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); + err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); + err |= native_window_set_usage(window, usage); - status_t result = NO_ERROR; - if (status == GL_FRAMEBUFFER_COMPLETE_OES) { - - renderScreenImplLocked(hw, reqWidth, reqHeight, minLayerZ, maxLayerZ, true); - - // Below we render the screenshot into the - // CpuConsumer using glReadPixels from our FBO. - // Some older drivers don't support the GL->CPU path so we - // have to wrap it with a CPU->CPU path, which is what - // glReadPixels essentially is. - - sp<Surface> sur = new Surface(producer); - ANativeWindow* window = sur.get(); - - if (native_window_api_connect(window, NATIVE_WINDOW_API_CPU) == NO_ERROR) { - int err = 0; - err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); - err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); - err |= native_window_set_usage(window, - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); - - if (err == NO_ERROR) { - ANativeWindowBuffer* buffer; - if (native_window_dequeue_buffer_and_wait(window, &buffer) == NO_ERROR) { - sp<GraphicBuffer> buf = static_cast<GraphicBuffer*>(buffer); - void* vaddr; - if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr) == NO_ERROR) { - glReadPixels(0, 0, buffer->stride, reqHeight, - GL_RGBA, GL_UNSIGNED_BYTE, vaddr); - buf->unlock(); + if (err == NO_ERROR) { + ANativeWindowBuffer* buffer; + /* TODO: Once we have the sync framework everywhere this can use + * server-side waits on the fence that dequeueBuffer returns. + */ + result = native_window_dequeue_buffer_and_wait(window, &buffer); + if (result == NO_ERROR) { + // create an EGLImage from the buffer so we can later + // turn it into a texture + EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, + EGL_NATIVE_BUFFER_ANDROID, buffer, NULL); + if (image != EGL_NO_IMAGE_KHR) { + GLuint tname, name; + if (!useReadPixels) { + // turn our EGLImage into a texture + glGenTextures(1, &tname); + glBindTexture(GL_TEXTURE_2D, tname); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image); + // create a Framebuffer Object to render into + glGenFramebuffersOES(1, &name); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); + glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, + GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tname, 0); + } else { + // since we're going to use glReadPixels() anyways, + // use an intermediate renderbuffer instead + glGenRenderbuffersOES(1, &tname); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); + glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, reqWidth, reqHeight); + // create a FBO to render into + glGenFramebuffersOES(1, &name); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, + GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); + } + + GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + if (status == GL_FRAMEBUFFER_COMPLETE_OES) { + // this will in fact render into our dequeued buffer + // via an FBO, which means we didn't have to create + // an EGLSurface and therefore we're not + // dependent on the context's EGLConfig. + renderScreenImplLocked(hw, reqWidth, reqHeight, + minLayerZ, maxLayerZ, true); + + if (useReadPixels) { + sp<GraphicBuffer> buf = static_cast<GraphicBuffer*>(buffer); + void* vaddr; + if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr) == NO_ERROR) { + glReadPixels(0, 0, buffer->stride, reqHeight, + GL_RGBA, GL_UNSIGNED_BYTE, vaddr); + buf->unlock(); + } + } + } else { + ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot"); + result = INVALID_OPERATION; } - window->queueBuffer(window, buffer, -1); + + // back to main framebuffer + glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); + glDeleteFramebuffersOES(1, &name); + if (!useReadPixels) { + glDeleteTextures(1, &tname); + } else { + glDeleteRenderbuffersOES(1, &tname); + } + // destroy our image + eglDestroyImageKHR(mEGLDisplay, image); + } else { + result = BAD_VALUE; } + window->queueBuffer(window, buffer, -1); } - native_window_api_disconnect(window, NATIVE_WINDOW_API_CPU); + } else { + result = BAD_VALUE; } - - } else { - ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES while taking screenshot"); - result = INVALID_OPERATION; + native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); } - // back to main framebuffer - glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); - glDeleteRenderbuffersOES(1, &tname); - glDeleteFramebuffersOES(1, &name); - DisplayDevice::setViewportAndProjection(hw); return result; @@ -2982,13 +2872,13 @@ int SurfaceFlinger::LayerVector::do_compare(const void* lhs, const sp<Layer>& l(*reinterpret_cast<const sp<Layer>*>(lhs)); const sp<Layer>& r(*reinterpret_cast<const sp<Layer>*>(rhs)); - uint32_t ls = l->currentState().layerStack; - uint32_t rs = r->currentState().layerStack; + uint32_t ls = l->getCurrentState().layerStack; + uint32_t rs = r->getCurrentState().layerStack; if (ls != rs) return ls - rs; - uint32_t lz = l->currentState().z; - uint32_t rz = r->currentState().z; + uint32_t lz = l->getCurrentState().z; + uint32_t rz = r->getCurrentState().z; if (lz != rz) return lz - rz; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 739099c..089c265 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -72,6 +72,13 @@ enum { eTransactionMask = 0x07 }; +enum GlesVersion { + GLES_VERSION_1_0 = 0x10000, + GLES_VERSION_1_1 = 0x10001, + GLES_VERSION_2_0 = 0x20000, + GLES_VERSION_3_0 = 0x30000, +}; + class SurfaceFlinger : public BinderService<SurfaceFlinger>, public BnSurfaceComposer, private IBinder::DeathRecipient, @@ -79,11 +86,11 @@ class SurfaceFlinger : public BinderService<SurfaceFlinger>, private HWComposer::EventHandler { public: - static char const* getServiceName() { + static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; } - SurfaceFlinger(); + SurfaceFlinger() ANDROID_API; enum { EVENT_VSYNC = HWC_EVENT_VSYNC @@ -121,6 +128,11 @@ public: // TODO: this should be made accessible only to HWComposer const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int id); + // return the version of the OpenGL ES composition context + GlesVersion getGlesVersion() const { + return mGlesVersion; + } + private: friend class Client; friend class DisplayEventConnection; @@ -298,14 +310,8 @@ private: const sp<const DisplayDevice>& hw, const sp<IGraphicBufferProducer>& producer, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ); - - status_t captureScreenImplCpuConsumerLocked( - const sp<const DisplayDevice>& hw, - const sp<IGraphicBufferProducer>& producer, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ); - + uint32_t minLayerZ, uint32_t maxLayerZ, + bool useReadPixels); /* ------------------------------------------------------------------------ * EGL @@ -385,12 +391,13 @@ private: * Debugging & dumpsys */ void listLayersLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const; + String8& result) const; void dumpStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const; + String8& result) const; void clearStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE); - void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const; + String8& result); + void dumpAllLocked(const Vector<String16>& args, size_t& index, + String8& result) const; bool startDdmConnection(); static void appendSfConfigString(String8& result); @@ -426,6 +433,7 @@ private: EGLConfig mEGLConfig; EGLDisplay mEGLDisplay; EGLint mEGLNativeVisualId; + GlesVersion mGlesVersion; sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_DISPLAY_TYPES]; // Can only accessed from the main thread, these members diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index 2869250..6912dc0 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -69,7 +69,7 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter) // reject buffers which have the wrong size int buf = item.mBuf; if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) { - releaseBufferLocked(buf, EGL_NO_SYNC_KHR); + releaseBufferLocked(buf, item.mGraphicBuffer, EGL_NO_SYNC_KHR); return NO_ERROR; } |