Merge change I0743a389 into eclair-mr2
* changes:
Close popup when Keyboard gets a CANCEL motion event.
diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h
index 884b5c1..749a977 100644
--- a/include/binder/IBinder.h
+++ b/include/binder/IBinder.h
@@ -52,7 +52,7 @@
DUMP_TRANSACTION = B_PACK_CHARS('_','D','M','P'),
INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
- // Corresponds to tfOneWay -- an asynchronous call.
+ // Corresponds to TF_ONE_WAY -- an asynchronous call.
FLAG_ONEWAY = 0x00000001
};
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 78306b2..3ab985d 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -68,6 +68,13 @@
static void shutdown();
+ // Call this to disable switching threads to background scheduling when
+ // receiving incoming IPC calls. This is specifically here for the
+ // Android system process, since it expects to have background apps calling
+ // in to it but doesn't want to acquire locks in its services while in
+ // the background.
+ static void disableBackgroundScheduling(bool disable);
+
private:
IPCThreadState();
~IPCThreadState();
@@ -93,9 +100,10 @@
void* cookie);
const sp<ProcessState> mProcess;
+ const pid_t mMyThreadId;
Vector<BBinder*> mPendingStrongDerefs;
Vector<RefBase::weakref_type*> mPendingWeakDerefs;
-
+
Parcel mIn;
Parcel mOut;
status_t mLastError;
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 49145e8..a845908 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -393,7 +393,10 @@
enum {
// If set, the string index is sorted by the string values (based
// on strcmp16()).
- SORTED_FLAG = 1<<0
+ SORTED_FLAG = 1<<0,
+
+ // String pool is encoded in UTF-8
+ UTF8_FLAG = 1<<8
};
uint32_t flags;
@@ -456,9 +459,11 @@
void* mOwnedData;
const ResStringPool_header* mHeader;
size_t mSize;
+ mutable Mutex mDecodeLock;
const uint32_t* mEntries;
const uint32_t* mEntryStyles;
- const char16_t* mStrings;
+ const void* mStrings;
+ char16_t** mCache;
uint32_t mStringPoolSize; // number of uint16_t
const uint32_t* mStyles;
uint32_t mStylePoolSize; // number of uint32_t
diff --git a/include/utils/String16.h b/include/utils/String16.h
index a2d22ee..07a0c11 100644
--- a/include/utils/String16.h
+++ b/include/utils/String16.h
@@ -49,12 +49,17 @@
// Version of strzcmp16 for comparing strings in different endianness.
int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2);
+// Convert UTF-8 to UTF-16 including surrogate pairs
+void utf8_to_utf16(const uint8_t *src, size_t srcLen, char16_t* dst, const size_t dstLen);
+
}
// ---------------------------------------------------------------------------
namespace android {
+// ---------------------------------------------------------------------------
+
class String8;
class TextOutput;
diff --git a/include/utils/String8.h b/include/utils/String8.h
index ecc5774..c4b18a4 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -60,6 +60,11 @@
/*
* Returns the UTF-8 length of "src".
*/
+size_t utf8_length_from_utf16(const char16_t *src, size_t src_len);
+
+/*
+ * Returns the UTF-8 length of "src".
+ */
size_t utf8_length_from_utf32(const char32_t *src, size_t src_len);
/*
@@ -120,6 +125,9 @@
size_t utf32_to_utf8(const char32_t* src, size_t src_len,
char* dst, size_t dst_len);
+size_t utf16_to_utf8(const char16_t* src, size_t src_len,
+ char* dst, size_t dst_len);
+
}
// ---------------------------------------------------------------------------
diff --git a/include/utils/threads.h b/include/utils/threads.h
index 0fc533f..130d83c 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -124,6 +124,24 @@
extern void androidSetCreateThreadFunc(android_create_thread_fn func);
+// ------------------------------------------------------------------
+// Extra functions working with raw pids.
+
+// Get pid for the current thread.
+extern pid_t androidGetTid();
+
+// Change the scheduling group of a particular thread. The group
+// should be one of the ANDROID_TGROUP constants. Returns BAD_VALUE if
+// grp is out of range, else another non-zero value with errno set if
+// the operation failed.
+extern int androidSetThreadSchedulingGroup(pid_t tid, int grp);
+
+// Change the priority AND scheduling group of a particular thread. The priority
+// should be one of the ANDROID_PRIORITY constants. Returns INVALID_OPERATION
+// if the priority set failed, else another value if just the group set failed;
+// in either case errno is set.
+extern int androidSetThreadPriority(pid_t tid, int prio);
+
#ifdef __cplusplus
}
#endif
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index b2a7db8..473f580 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -292,6 +292,7 @@
static bool gHaveTLS = false;
static pthread_key_t gTLS = 0;
static bool gShutdown = false;
+static bool gDisableBackgroundScheduling = false;
IPCThreadState* IPCThreadState::self()
{
@@ -332,6 +333,11 @@
}
}
+void IPCThreadState::disableBackgroundScheduling(bool disable)
+{
+ gDisableBackgroundScheduling = disable;
+}
+
sp<ProcessState> IPCThreadState::process()
{
return mProcess;
@@ -386,6 +392,11 @@
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
+ // This thread may have been spawned by a thread that was in the background
+ // scheduling group, so first we will make sure it is in the default/foreground
+ // one to avoid performing an initial transaction in the background.
+ androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
+
status_t result;
do {
int32_t cmd;
@@ -427,19 +438,13 @@
}
// After executing the command, ensure that the thread is returned to the
- // default cgroup and priority before rejoining the pool. This is a failsafe
- // in case the command implementation failed to properly restore the thread's
- // scheduling parameters upon completion.
- int my_id;
-#ifdef HAVE_GETTID
- my_id = gettid();
-#else
- my_id = getpid();
-#endif
- if (!set_sched_policy(my_id, SP_FOREGROUND)) {
- // success; reset the priority as well
- setpriority(PRIO_PROCESS, my_id, ANDROID_PRIORITY_NORMAL);
- }
+ // default cgroup before rejoining the pool. The driver takes care of
+ // restoring the priority, but doesn't do anything with cgroups so we
+ // need to take care of that here in userspace. Note that we do make
+ // sure to go in the foreground after executing a transaction, but
+ // there are other callbacks into user code that could have changed
+ // our group so we want to make absolutely sure it is put back.
+ androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
@@ -583,10 +588,10 @@
}
IPCThreadState::IPCThreadState()
- : mProcess(ProcessState::self())
+ : mProcess(ProcessState::self()), mMyThreadId(androidGetTid())
{
pthread_setspecific(gTLS, this);
- clearCaller();
+ clearCaller();
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
}
@@ -930,6 +935,17 @@
mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid;
+ bool doBackground = !gDisableBackgroundScheduling &&
+ getpriority(PRIO_PROCESS, mMyThreadId)
+ >= ANDROID_PRIORITY_BACKGROUND;
+ if (doBackground) {
+ // We have inherited a background priority from the caller.
+ // Ensure this thread is in the background scheduling class,
+ // since the driver won't modify scheduling classes for us.
+ androidSetThreadSchedulingGroup(mMyThreadId,
+ ANDROID_TGROUP_BG_NONINTERACT);
+ }
+
//LOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
Parcel reply;
@@ -967,6 +983,13 @@
mCallingPid = origPid;
mCallingUid = origUid;
+ if (doBackground) {
+ // We moved to the background scheduling group to execute
+ // this transaction, so now that we are done go back in the
+ // foreground.
+ androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
+ }
+
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 450af8d..afca814 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -229,12 +229,12 @@
// --------------------------------------------------------------------
ResStringPool::ResStringPool()
- : mError(NO_INIT), mOwnedData(NULL)
+ : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL)
{
}
ResStringPool::ResStringPool(const void* data, size_t size, bool copyData)
- : mError(NO_INIT), mOwnedData(NULL)
+ : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL)
{
setTo(data, size, copyData);
}
@@ -296,7 +296,17 @@
(int)size);
return (mError=BAD_TYPE);
}
- mStrings = (const char16_t*)
+
+ size_t charSize;
+ if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
+ charSize = sizeof(uint8_t);
+ mCache = (char16_t**)malloc(sizeof(char16_t**)*mHeader->stringCount);
+ memset(mCache, 0, sizeof(char16_t**)*mHeader->stringCount);
+ } else {
+ charSize = sizeof(char16_t);
+ }
+
+ mStrings = (const void*)
(((const uint8_t*)data)+mHeader->stringsStart);
if (mHeader->stringsStart >= (mHeader->header.size-sizeof(uint16_t))) {
LOGW("Bad string block: string pool starts at %d, after total size %d\n",
@@ -305,7 +315,7 @@
}
if (mHeader->styleCount == 0) {
mStringPoolSize =
- (mHeader->header.size-mHeader->stringsStart)/sizeof(uint16_t);
+ (mHeader->header.size-mHeader->stringsStart)/charSize;
} else {
// check invariant: styles follow the strings
if (mHeader->stylesStart <= mHeader->stringsStart) {
@@ -314,7 +324,7 @@
return (mError=BAD_TYPE);
}
mStringPoolSize =
- (mHeader->stylesStart-mHeader->stringsStart)/sizeof(uint16_t);
+ (mHeader->stylesStart-mHeader->stringsStart)/charSize;
}
// check invariant: stringCount > 0 requires a string pool to exist
@@ -329,13 +339,19 @@
for (i=0; i<mHeader->stringCount; i++) {
e[i] = dtohl(mEntries[i]);
}
- char16_t* s = const_cast<char16_t*>(mStrings);
- for (i=0; i<mStringPoolSize; i++) {
- s[i] = dtohs(mStrings[i]);
+ if (!(mHeader->flags&ResStringPool_header::UTF8_FLAG)) {
+ const char16_t* strings = (const char16_t*)mStrings;
+ char16_t* s = const_cast<char16_t*>(strings);
+ for (i=0; i<mStringPoolSize; i++) {
+ s[i] = dtohs(strings[i]);
+ }
}
}
- if (mStrings[mStringPoolSize-1] != 0) {
+ if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
+ ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
+ (!mHeader->flags&ResStringPool_header::UTF8_FLAG &&
+ ((char16_t*)mStrings)[mStringPoolSize-1] != 0)) {
LOGW("Bad string block: last string is not 0-terminated\n");
return (mError=BAD_TYPE);
}
@@ -410,24 +426,67 @@
free(mOwnedData);
mOwnedData = NULL;
}
+ if (mHeader != NULL && mCache != NULL) {
+ for (size_t x = 0; x < mHeader->stringCount; x++) {
+ if (mCache[x] != NULL) {
+ free(mCache[x]);
+ mCache[x] = NULL;
+ }
+ }
+ free(mCache);
+ mCache = NULL;
+ }
}
+#define DECODE_LENGTH(str, chrsz, len) \
+ len = *(str); \
+ if (*(str)&(1<<(chrsz*8-1))) { \
+ (str)++; \
+ len = (((len)&((1<<(chrsz*8-1))-1))<<(chrsz*8)) + *(str); \
+ } \
+ (str)++;
+
const uint16_t* ResStringPool::stringAt(size_t idx, size_t* outLen) const
{
if (mError == NO_ERROR && idx < mHeader->stringCount) {
- const uint32_t off = (mEntries[idx]/sizeof(uint16_t));
+ const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
+ const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t));
if (off < (mStringPoolSize-1)) {
- const char16_t* str = mStrings+off;
- *outLen = *str;
- if ((*str)&0x8000) {
- str++;
- *outLen = (((*outLen)&0x7fff)<<16) + *str;
- }
- if ((uint32_t)(str+1+*outLen-mStrings) < mStringPoolSize) {
- return str+1;
+ if (!isUTF8) {
+ const char16_t* strings = (char16_t*)mStrings;
+ const char16_t* str = strings+off;
+ DECODE_LENGTH(str, sizeof(char16_t), *outLen)
+ if ((uint32_t)(str+*outLen-strings) < mStringPoolSize) {
+ return str;
+ } else {
+ LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
+ (int)idx, (int)(str+*outLen-strings), (int)mStringPoolSize);
+ }
} else {
- LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
- (int)idx, (int)(str+1+*outLen-mStrings), (int)mStringPoolSize);
+ const uint8_t* strings = (uint8_t*)mStrings;
+ const uint8_t* str = strings+off;
+ DECODE_LENGTH(str, sizeof(uint8_t), *outLen)
+ size_t encLen;
+ DECODE_LENGTH(str, sizeof(uint8_t), encLen)
+ if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
+ AutoMutex lock(mDecodeLock);
+ if (mCache[idx] != NULL) {
+ return mCache[idx];
+ }
+ char16_t *u16str = (char16_t *)calloc(*outLen+1, sizeof(char16_t));
+ if (!u16str) {
+ LOGW("No memory when trying to allocate decode cache for string #%d\n",
+ (int)idx);
+ return NULL;
+ }
+ const unsigned char *u8src = reinterpret_cast<const unsigned char *>(str);
+ utf8_to_utf16(u8src, encLen, u16str, *outLen);
+ mCache[idx] = u16str;
+ return u16str;
+ } else {
+ LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
+ (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
+ }
}
} else {
LOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
@@ -466,6 +525,10 @@
size_t len;
+ // TODO optimize searching for UTF-8 strings taking into account
+ // the cache fill to determine when to convert the searched-for
+ // string key to UTF-8.
+
if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
// Do a binary search for the string...
ssize_t l = 0;
@@ -1043,6 +1106,7 @@
void ResXMLTree::uninit()
{
mError = NO_INIT;
+ mStrings.uninit();
if (mOwnedData) {
free(mOwnedData);
mOwnedData = NULL;
diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp
index aef67f2..eab7b2b 100644
--- a/libs/utils/String16.cpp
+++ b/libs/utils/String16.cpp
@@ -172,10 +172,6 @@
: 0);
}
-// ---------------------------------------------------------------------------
-
-namespace android {
-
static inline size_t
utf8_char_len(uint8_t ch)
{
@@ -215,8 +211,38 @@
//printf("Char at %p: len=%d, utf-16=%p\n", src, length, (void*)result);
}
+void
+utf8_to_utf16(const uint8_t *src, size_t srcLen,
+ char16_t* dst, const size_t dstLen)
+{
+ const uint8_t* const end = src + srcLen;
+ const char16_t* const dstEnd = dst + dstLen;
+ while (src < end && dst < dstEnd) {
+ size_t len = utf8_char_len(*src);
+ uint32_t codepoint = utf8_to_utf32((const uint8_t*)src, len);
+
+ // Convert the UTF32 codepoint to one or more UTF16 codepoints
+ if (codepoint <= 0xFFFF) {
+ // Single UTF16 character
+ *dst++ = (char16_t) codepoint;
+ } else {
+ // Multiple UTF16 characters with surrogates
+ codepoint = codepoint - 0x10000;
+ *dst++ = (char16_t) ((codepoint >> 10) + 0xD800);
+ *dst++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00);
+ }
+
+ src += len;
+ }
+ if (dst < dstEnd) {
+ *dst = 0;
+ }
+}
+
// ---------------------------------------------------------------------------
+namespace android {
+
static SharedBuffer* gEmptyStringBuf = NULL;
static char16_t* gEmptyString = NULL;
@@ -260,30 +286,14 @@
p += utf8len;
}
- SharedBuffer* buf = SharedBuffer::alloc((chars+1)*sizeof(char16_t));
+ size_t bufSize = (chars+1)*sizeof(char16_t);
+ SharedBuffer* buf = SharedBuffer::alloc(bufSize);
if (buf) {
p = in;
char16_t* str = (char16_t*)buf->data();
- char16_t* d = str;
- while (p < end) {
- size_t len = utf8_char_len(*p);
- uint32_t codepoint = utf8_to_utf32((const uint8_t*)p, len);
-
- // Convert the UTF32 codepoint to one or more UTF16 codepoints
- if (codepoint <= 0xFFFF) {
- // Single UTF16 character
- *d++ = (char16_t) codepoint;
- } else {
- // Multiple UTF16 characters with surrogates
- codepoint = codepoint - 0x10000;
- *d++ = (char16_t) ((codepoint >> 10) + 0xD800);
- *d++ = (char16_t) ((codepoint & 0x3FF) + 0xDC00);
- }
-
- p += len;
- }
- *d = 0;
+ utf8_to_utf16((const uint8_t*)p, len, str, bufSize);
+
//printf("Created UTF-16 string from UTF-8 \"%s\":", in);
//printHexData(1, str, buf->size(), 16, 1);
//printf("\n");
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
index e908ec1..3a34838 100644
--- a/libs/utils/String8.cpp
+++ b/libs/utils/String8.cpp
@@ -208,10 +208,23 @@
return getEmptyString();
}
-// Note: not dealing with expanding surrogate pairs.
static char* allocFromUTF16(const char16_t* in, size_t len)
{
- return allocFromUTF16OrUTF32<char16_t, size_t>(in, len);
+ if (len == 0) return getEmptyString();
+
+ const size_t bytes = utf8_length_from_utf16(in, len);
+
+ SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
+ LOG_ASSERT(buf, "Unable to allocate shared buffer");
+ if (buf) {
+ char* str = (char*)buf->data();
+
+ utf16_to_utf8(in, len, str, bytes+1);
+
+ return str;
+ }
+
+ return getEmptyString();
}
static char* allocFromUTF32(const char32_t* in, size_t len)
@@ -762,6 +775,26 @@
return ret;
}
+size_t utf8_length_from_utf16(const char16_t *src, size_t src_len)
+{
+ if (src == NULL || src_len == 0) {
+ return 0;
+ }
+ size_t ret = 0;
+ const char16_t* const end = src + src_len;
+ while (src < end) {
+ if ((*src & 0xFC00) == 0xD800 && (src + 1) < end
+ && (*++src & 0xFC00) == 0xDC00) {
+ // surrogate pairs are always 4 bytes.
+ ret += 4;
+ src++;
+ } else {
+ ret += android::utf32_to_utf8_bytes((char32_t) *src++);
+ }
+ }
+ return ret;
+}
+
static int32_t utf32_at_internal(const char* cur, size_t *num_read)
{
const char first_char = *cur;
@@ -848,3 +881,33 @@
}
return cur - dst;
}
+
+size_t utf16_to_utf8(const char16_t* src, size_t src_len,
+ char* dst, size_t dst_len)
+{
+ if (src == NULL || src_len == 0 || dst == NULL || dst_len == 0) {
+ return 0;
+ }
+ const char16_t* cur_utf16 = src;
+ const char16_t* const end_utf16 = src + src_len;
+ char *cur = dst;
+ const char* const end = dst + dst_len;
+ while (cur_utf16 < end_utf16 && cur < end) {
+ char32_t utf32;
+ // surrogate pairs
+ if ((*cur_utf16 & 0xFC00) == 0xD800 && (cur_utf16 + 1) < end_utf16) {
+ utf32 = (*cur_utf16++ - 0xD800) << 10;
+ utf32 |= *cur_utf16++ - 0xDC00;
+ utf32 += 0x10000;
+ } else {
+ utf32 = (char32_t) *cur_utf16++;
+ }
+ size_t len = android::utf32_to_utf8_bytes(utf32);
+ android::utf32_to_utf8((uint8_t*)cur, utf32, len);
+ cur += len;
+ }
+ if (cur < end) {
+ *cur = '\0';
+ }
+ return cur - dst;
+}
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index ec3db09..6ca2603 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -20,6 +20,8 @@
#include <utils/threads.h>
#include <utils/Log.h>
+#include <cutils/sched_policy.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
@@ -269,6 +271,53 @@
gCreateThreadFn = func;
}
+pid_t androidGetTid()
+{
+#ifdef HAVE_GETTID
+ return gettid();
+#else
+ return getpid();
+#endif
+}
+
+int androidSetThreadSchedulingGroup(pid_t tid, int grp)
+{
+ if (grp > ANDROID_TGROUP_MAX || grp < 0) {
+ return BAD_VALUE;
+ }
+
+ if (set_sched_policy(tid, (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+ SP_BACKGROUND : SP_FOREGROUND)) {
+ return PERMISSION_DENIED;
+ }
+
+ return NO_ERROR;
+}
+
+int androidSetThreadPriority(pid_t tid, int pri)
+{
+ int rc = 0;
+ int lasterr = 0;
+
+ 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) {
+ lasterr = errno;
+ }
+
+ if (setpriority(PRIO_PROCESS, tid, pri) < 0) {
+ rc = INVALID_OPERATION;
+ } else {
+ errno = lasterr;
+ }
+
+ return rc;
+}
+
namespace android {
/*