More JNI exception-throwing cleanup.

There are a few (unimportant) bug fixes here. There were several attempts to
throw exceptions in situations where there's already a pending exception.

There were also cases where the code was wrong; it was checking for a NULL
return from Get*ArrayElements and throwing NPE, but passing NULL is an error
that causes a crash and a NULL return means an exception has already been
thrown. I didn't want to get into the Scoped* classes just yet, but that
was by far the easiest way to fix this.

Change-Id: I0b31160ee51b96e82539f6514b8412b149dba7c3
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 65b5990..8ea7e90 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -2,16 +2,16 @@
 **
 ** Copyright 2006, 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 
+** 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 
+**     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 
+** 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.
 */
 
@@ -24,6 +24,8 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
+#include "ScopedStringChars.h"
+#include "ScopedUtfChars.h"
 #include "android_util_Binder.h"
 #include <utils/misc.h>
 #include <android_runtime/AndroidRuntime.h>
@@ -121,8 +123,8 @@
 
     LOGV("openAsset in %p (Java object %p)\n", am, clazz);
 
-    if (fileName == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "fileName");
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
         return -1;
     }
 
@@ -132,15 +134,12 @@
         return -1;
     }
 
-    const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
-    Asset* a = am->open(fileName8, (Asset::AccessMode)mode);
+    Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
 
     if (a == NULL) {
-        jniThrowException(env, "java/io/FileNotFoundException", fileName8);
-        env->ReleaseStringUTFChars(fileName, fileName8);
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
         return -1;
     }
-    env->ReleaseStringUTFChars(fileName, fileName8);
 
     //printf("Created Asset Stream: %p\n", a);
 
@@ -152,30 +151,30 @@
     off64_t startOffset, length;
     int fd = a->openFileDescriptor(&startOffset, &length);
     delete a;
-    
+
     if (fd < 0) {
         jniThrowException(env, "java/io/FileNotFoundException",
                 "This file can not be opened as a file descriptor; it is probably compressed");
         return NULL;
     }
-    
+
     jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
     if (offsets == NULL) {
         close(fd);
         return NULL;
     }
-    
+
     offsets[0] = startOffset;
     offsets[1] = length;
-    
+
     env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
-    
+
     jobject fileDesc = newFileDescriptor(env, fd);
     if (fileDesc == NULL) {
         close(fd);
         return NULL;
     }
-    
+
     return newParcelFileDescriptor(env, fileDesc);
 }
 
@@ -189,20 +188,17 @@
 
     LOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
 
-    if (fileName == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "fileName");
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
         return NULL;
     }
 
-    const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
-    Asset* a = am->open(fileName8, Asset::ACCESS_RANDOM);
+    Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
 
     if (a == NULL) {
-        jniThrowException(env, "java/io/FileNotFoundException", fileName8);
-        env->ReleaseStringUTFChars(fileName, fileName8);
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
         return NULL;
     }
-    env->ReleaseStringUTFChars(fileName, fileName8);
 
     //printf("Created Asset Stream: %p\n", a);
 
@@ -221,8 +217,8 @@
 
     LOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
 
-    if (fileName == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "fileName");
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
         return -1;
     }
 
@@ -232,17 +228,14 @@
         return -1;
     }
 
-    const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
     Asset* a = cookie
-        ? am->openNonAsset((void*)cookie, fileName8, (Asset::AccessMode)mode)
-        : am->openNonAsset(fileName8, (Asset::AccessMode)mode);
+        ? am->openNonAsset((void*)cookie, fileName8.c_str(), (Asset::AccessMode)mode)
+        : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
 
     if (a == NULL) {
-        jniThrowException(env, "java/io/FileNotFoundException", fileName8);
-        env->ReleaseStringUTFChars(fileName, fileName8);
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
         return -1;
     }
-    env->ReleaseStringUTFChars(fileName, fileName8);
 
     //printf("Created Asset Stream: %p\n", a);
 
@@ -261,22 +254,19 @@
 
     LOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
 
-    if (fileName == NULL ) {
-        jniThrowException(env, "java/lang/NullPointerException", "fileName");
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
         return NULL;
     }
 
-    const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
     Asset* a = cookie
-        ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_RANDOM)
-        : am->openNonAsset(fileName8, Asset::ACCESS_RANDOM);
+        ? am->openNonAsset((void*)cookie, fileName8.c_str(), Asset::ACCESS_RANDOM)
+        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
 
     if (a == NULL) {
-        jniThrowException(env, "java/io/FileNotFoundException", fileName8);
-        env->ReleaseStringUTFChars(fileName, fileName8);
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
         return NULL;
     }
-    env->ReleaseStringUTFChars(fileName, fileName8);
 
     //printf("Created Asset Stream: %p\n", a);
 
@@ -291,19 +281,15 @@
         return NULL;
     }
 
-    if (fileName == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "fileName");
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
         return NULL;
     }
 
-    const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
-
-    AssetDir* dir = am->openDir(fileName8);
-
-    env->ReleaseStringUTFChars(fileName, fileName8);
+    AssetDir* dir = am->openDir(fileName8.c_str());
 
     if (dir == NULL) {
-        jniThrowException(env, "java/io/FileNotFoundException", fileName8);
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
         return NULL;
     }
 
@@ -347,7 +333,7 @@
     //printf("Destroying Asset Stream: %p\n", a);
 
     if (a == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "asset");
+        jniThrowNullPointerException(env, "asset");
         return;
     }
 
@@ -360,7 +346,7 @@
     Asset* a = (Asset*)asset;
 
     if (a == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "asset");
+        jniThrowNullPointerException(env, "asset");
         return -1;
     }
 
@@ -376,14 +362,14 @@
     Asset* a = (Asset*)asset;
 
     if (a == NULL || bArray == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "asset");
+        jniThrowNullPointerException(env, "asset");
         return -1;
     }
 
     if (len == 0) {
         return 0;
     }
-    
+
     jsize bLen = env->GetArrayLength(bArray);
     if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
@@ -409,7 +395,7 @@
     Asset* a = (Asset*)asset;
 
     if (a == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "asset");
+        jniThrowNullPointerException(env, "asset");
         return -1;
     }
 
@@ -423,7 +409,7 @@
     Asset* a = (Asset*)asset;
 
     if (a == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "asset");
+        jniThrowNullPointerException(env, "asset");
         return -1;
     }
 
@@ -436,7 +422,7 @@
     Asset* a = (Asset*)asset;
 
     if (a == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "asset");
+        jniThrowNullPointerException(env, "asset");
         return -1;
     }
 
@@ -446,9 +432,9 @@
 static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
                                                        jstring path)
 {
-    if (path == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "path");
-        return JNI_FALSE;
+    ScopedUtfChars path8(env, path);
+    if (path8.c_str() == NULL) {
+        return NULL;
     }
 
     AssetManager* am = assetManagerForJavaObject(env, clazz);
@@ -456,12 +442,8 @@
         return JNI_FALSE;
     }
 
-    const char* path8 = env->GetStringUTFChars(path, NULL);
-
     void* cookie;
-    bool res = am->addAssetPath(String8(path8), &cookie);
-
-    env->ReleaseStringUTFChars(path, path8);
+    bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
 
     return (res) ? (jint)cookie : 0;
 }
@@ -478,21 +460,17 @@
 static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
                                                 jstring locale)
 {
-    if (locale == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "locale");
+    ScopedUtfChars locale8(env, locale);
+    if (locale8.c_str() == NULL) {
         return;
     }
 
-    const char* locale8 = env->GetStringUTFChars(locale, NULL);
-
     AssetManager* am = assetManagerForJavaObject(env, clazz);
     if (am == NULL) {
         return;
     }
 
-    am->setLocale(locale8);
-
-    env->ReleaseStringUTFChars(locale, locale8);
+    am->setLocale(locale8.c_str());
 }
 
 static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
@@ -543,9 +521,9 @@
 
     ResTable_config config;
     memset(&config, 0, sizeof(config));
-    
+
     const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
-    
+
     config.mcc = (uint16_t)mcc;
     config.mnc = (uint16_t)mnc;
     config.orientation = (uint8_t)orientation;
@@ -563,7 +541,7 @@
     config.sdkVersion = (uint16_t)sdkVersion;
     config.minorVersion = 0;
     am->setConfiguration(config, locale8);
-    
+
     if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
 }
 
@@ -572,8 +550,8 @@
                                                             jstring defType,
                                                             jstring defPackage)
 {
-    if (name == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "name");
+    ScopedStringChars name16(env, name);
+    if (name16.get() == NULL) {
         return 0;
     }
 
@@ -582,8 +560,6 @@
         return 0;
     }
 
-    const char16_t* name16 = env->GetStringChars(name, NULL);
-    jsize nameLen = env->GetStringLength(name);
     const char16_t* defType16 = defType
         ? env->GetStringChars(defType, NULL) : NULL;
     jsize defTypeLen = defType
@@ -594,7 +570,7 @@
         ? env->GetStringLength(defPackage) : 0;
 
     jint ident = am->getResources().identifierForName(
-        name16, nameLen, defType16, defTypeLen, defPackage16, defPackageLen);
+        name16.get(), name16.size(), defType16, defTypeLen, defPackage16, defPackageLen);
 
     if (defPackage16) {
         env->ReleaseStringChars(defPackage, defPackage16);
@@ -602,7 +578,6 @@
     if (defType16) {
         env->ReleaseStringChars(defType, defType16);
     }
-    env->ReleaseStringChars(name, name16);
 
     return ident;
 }
@@ -614,12 +589,12 @@
     if (am == NULL) {
         return NULL;
     }
-    
+
     ResTable::resource_name name;
     if (!am->getResources().getResourceName(resid, &name)) {
         return NULL;
     }
-    
+
     String16 str;
     if (name.package != NULL) {
         str.setTo(name.package, name.packageLen);
@@ -638,7 +613,7 @@
         }
         str.append(name.name, name.nameLen);
     }
-    
+
     return env->NewString((const jchar*)str.string(), str.size());
 }
 
@@ -649,16 +624,16 @@
     if (am == NULL) {
         return NULL;
     }
-    
+
     ResTable::resource_name name;
     if (!am->getResources().getResourceName(resid, &name)) {
         return NULL;
     }
-    
+
     if (name.package != NULL) {
         return env->NewString((const jchar*)name.package, name.packageLen);
     }
-    
+
     return NULL;
 }
 
@@ -669,16 +644,16 @@
     if (am == NULL) {
         return NULL;
     }
-    
+
     ResTable::resource_name name;
     if (!am->getResources().getResourceName(resid, &name)) {
         return NULL;
     }
-    
+
     if (name.type != NULL) {
         return env->NewString((const jchar*)name.type, name.typeLen);
     }
-    
+
     return NULL;
 }
 
@@ -689,16 +664,16 @@
     if (am == NULL) {
         return NULL;
     }
-    
+
     ResTable::resource_name name;
     if (!am->getResources().getResourceName(resid, &name)) {
         return NULL;
     }
-    
+
     if (name.name != NULL) {
         return env->NewString((const jchar*)name.name, name.nameLen);
     }
-    
+
     return NULL;
 }
 
@@ -746,10 +721,10 @@
         return 0;
     }
     const ResTable& res(am->getResources());
-    
+
     // Now lock down the resource object and start pulling stuff from it.
     res.lock();
-    
+
     ssize_t block = -1;
     Res_value value;
 
@@ -770,7 +745,7 @@
     if (block < 0) {
         return block;
     }
-    
+
     uint32_t ref = ident;
     if (resolve) {
         block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
@@ -881,25 +856,9 @@
 {
     ResTable::Theme* theme = (ResTable::Theme*)themeInt;
     const ResTable& res(theme->getResTable());
-    
-    if (tag == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "tag");
-        return;
-    }
-    
-    const char* tag8 = env->GetStringUTFChars(tag, NULL);
-    const char* prefix8 = NULL;
-    if (prefix != NULL) {
-        prefix8 = env->GetStringUTFChars(prefix, NULL);
-    }
-    
+
     // XXX Need to use params.
     theme->dumpToLog();
-    
-    if (prefix8 != NULL) {
-        env->ReleaseStringUTFChars(prefix, prefix8);
-    }
-    env->ReleaseStringUTFChars(tag, tag8);
 }
 
 static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
@@ -912,21 +871,21 @@
                                                         jintArray outIndices)
 {
     if (themeToken == 0) {
-        jniThrowException(env, "java/lang/NullPointerException", "theme token");
+        jniThrowNullPointerException(env, "theme token");
         return JNI_FALSE;
     }
     if (attrs == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "attrs");
+        jniThrowNullPointerException(env, "attrs");
         return JNI_FALSE;
     }
     if (outValues == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "out values");
+        jniThrowNullPointerException(env, "out values");
         return JNI_FALSE;
     }
 
     DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
         themeToken, defStyleAttr, defStyleRes, xmlParserToken));
-        
+
     ResTable::Theme* theme = (ResTable::Theme*)themeToken;
     const ResTable& res = theme->getResTable();
     ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
@@ -942,7 +901,6 @@
 
     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
     if (src == NULL) {
-        jniThrowException(env, "java/lang/OutOfMemoryError", "");
         return JNI_FALSE;
     }
 
@@ -950,7 +908,6 @@
     jint* dest = baseDest;
     if (dest == NULL) {
         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-        jniThrowException(env, "java/lang/OutOfMemoryError", "");
         return JNI_FALSE;
     }
 
@@ -1025,7 +982,7 @@
         const uint32_t curIdent = (uint32_t)src[ii];
 
         DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
-        
+
         // Try to find a value for this attribute...  we prioritize values
         // coming from, first XML attributes, then XML style, then default
         // style, and finally the theme.
@@ -1128,12 +1085,12 @@
         dest[STYLE_RESOURCE_ID] = resid;
         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
         dest[STYLE_DENSITY] = config.density;
-        
+
         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
             indicesIdx++;
             indices[indicesIdx] = ii;
         }
-        
+
         dest += STYLE_NUM_ENTRIES;
     }
 
@@ -1156,18 +1113,18 @@
                                                         jintArray outIndices)
 {
     if (xmlParserToken == 0) {
-        jniThrowException(env, "java/lang/NullPointerException", "xmlParserToken");
+        jniThrowNullPointerException(env, "xmlParserToken");
         return JNI_FALSE;
     }
     if (attrs == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "attrs");
+        jniThrowNullPointerException(env, "attrs");
         return JNI_FALSE;
     }
     if (outValues == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "out values");
+        jniThrowNullPointerException(env, "out values");
         return JNI_FALSE;
     }
-    
+
     AssetManager* am = assetManagerForJavaObject(env, clazz);
     if (am == NULL) {
         return JNI_FALSE;
@@ -1176,28 +1133,26 @@
     ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
     ResTable_config config;
     Res_value value;
-    
+
     const jsize NI = env->GetArrayLength(attrs);
     const jsize NV = env->GetArrayLength(outValues);
     if (NV < (NI*STYLE_NUM_ENTRIES)) {
         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
         return JNI_FALSE;
     }
-    
+
     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
     if (src == NULL) {
-        jniThrowException(env, "java/lang/OutOfMemoryError", "");
         return JNI_FALSE;
     }
-    
+
     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
     jint* dest = baseDest;
     if (dest == NULL) {
         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-        jniThrowException(env, "java/lang/OutOfMemoryError", "");
         return JNI_FALSE;
     }
-    
+
     jint* indices = NULL;
     int indicesIdx = 0;
     if (outIndices != NULL) {
@@ -1208,27 +1163,27 @@
 
     // Now lock down the resource object and start pulling stuff from it.
     res.lock();
-    
+
     // Retrieve the XML attributes, if requested.
     const jsize NX = xmlParser->getAttributeCount();
     jsize ix=0;
     uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
-    
+
     static const ssize_t kXmlBlock = 0x10000000;
-    
+
     // Now iterate through all of the attributes that the client has requested,
     // filling in each with whatever data we can find.
     ssize_t block = 0;
     uint32_t typeSetFlags;
     for (jsize ii=0; ii<NI; ii++) {
         const uint32_t curIdent = (uint32_t)src[ii];
-        
+
         // Try to find a value for this attribute...
         value.dataType = Res_value::TYPE_NULL;
         value.data = 0;
         typeSetFlags = 0;
         config.density = 0;
-        
+
         // Skip through XML attributes until the end or the next possible match.
         while (ix < NX && curIdent > curXmlAttr) {
             ix++;
@@ -1241,7 +1196,7 @@
             ix++;
             curXmlAttr = xmlParser->getAttributeNameResID(ix);
         }
-        
+
         //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
         uint32_t resid = 0;
         if (value.dataType != Res_value::TYPE_NULL) {
@@ -1257,14 +1212,14 @@
 #endif
             if (newBlock >= 0) block = newBlock;
         }
-        
+
         // Deal with the special @null value -- it turns back to TYPE_NULL.
         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
             value.dataType = Res_value::TYPE_NULL;
         }
-        
+
         //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
-        
+
         // Write the final value back to Java.
         dest[STYLE_TYPE] = value.dataType;
         dest[STYLE_DATA] = value.data;
@@ -1273,25 +1228,25 @@
         dest[STYLE_RESOURCE_ID] = resid;
         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
         dest[STYLE_DENSITY] = config.density;
-        
+
         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
             indicesIdx++;
             indices[indicesIdx] = ii;
         }
-        
+
         dest += STYLE_NUM_ENTRIES;
     }
-    
+
     res.unlock();
-    
+
     if (indices != NULL) {
         indices[0] = indicesIdx;
         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
     }
-    
+
     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-    
+
     return JNI_TRUE;
 }
 
@@ -1303,12 +1258,12 @@
         return 0;
     }
     const ResTable& res(am->getResources());
-    
+
     res.lock();
     const ResTable::bag_entry* defStyleEnt = NULL;
     ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
     res.unlock();
-    
+
     return bagOff;
 }
 
@@ -1317,10 +1272,10 @@
                                                         jintArray outValues)
 {
     if (outValues == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "out values");
+        jniThrowNullPointerException(env, "out values");
         return JNI_FALSE;
     }
-    
+
     AssetManager* am = assetManagerForJavaObject(env, clazz);
     if (am == NULL) {
         return JNI_FALSE;
@@ -1329,25 +1284,25 @@
     ResTable_config config;
     Res_value value;
     ssize_t block;
-    
+
     const jsize NV = env->GetArrayLength(outValues);
-    
+
     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
     jint* dest = baseDest;
     if (dest == NULL) {
         jniThrowException(env, "java/lang/OutOfMemoryError", "");
         return JNI_FALSE;
     }
-    
+
     // Now lock down the resource object and start pulling stuff from it.
     res.lock();
-    
+
     const ResTable::bag_entry* arrayEnt = NULL;
     uint32_t arrayTypeSetFlags = 0;
     ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
     const ResTable::bag_entry* endArrayEnt = arrayEnt +
         (bagOff >= 0 ? bagOff : 0);
-    
+
     int i = 0;
     uint32_t typeSetFlags;
     while (i < NV && arrayEnt < endArrayEnt) {
@@ -1355,7 +1310,7 @@
         typeSetFlags = arrayTypeSetFlags;
         config.density = 0;
         value = arrayEnt->map.value;
-                
+
         uint32_t resid = 0;
         if (value.dataType != Res_value::TYPE_NULL) {
             // Take care of resolving the found resource to its final value.
@@ -1389,13 +1344,13 @@
         i+= STYLE_NUM_ENTRIES;
         arrayEnt++;
     }
-    
+
     i /= STYLE_NUM_ENTRIES;
-    
+
     res.unlock();
-    
+
     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
-    
+
     return i;
 }
 
@@ -1410,22 +1365,19 @@
 
     LOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
 
-    if (fileName == NULL) {
-        jniThrowException(env, "java/lang/NullPointerException", "fileName");
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
         return 0;
     }
 
-    const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
     Asset* a = cookie
-        ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_BUFFER)
-        : am->openNonAsset(fileName8, Asset::ACCESS_BUFFER);
+        ? am->openNonAsset((void*)cookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
+        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER);
 
     if (a == NULL) {
-        jniThrowException(env, "java/io/FileNotFoundException", fileName8);
-        env->ReleaseStringUTFChars(fileName, fileName8);
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
         return 0;
     }
-    env->ReleaseStringUTFChars(fileName, fileName8);
 
     ResXMLTree* block = new ResXMLTree();
     status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
@@ -1457,7 +1409,6 @@
 
     jintArray array = env->NewIntArray(N * 2);
     if (array == NULL) {
-        jniThrowException(env, "java/lang/OutOfMemoryError", "");
         res.unlockBag(startOfBag);
         return NULL;
     }
@@ -1468,20 +1419,20 @@
         jint stringIndex = -1;
         jint stringBlock = 0;
         value = bag->map.value;
-        
+
         // Take care of resolving the found resource to its final value.
         stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
         if (value.dataType == Res_value::TYPE_STRING) {
             stringIndex = value.data;
         }
-        
+
 #if THROW_ON_BAD_ID
         if (stringBlock == BAD_INDEX) {
             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
             return array;
         }
 #endif
-    
+
         //todo: It might be faster to allocate a C array to contain
         //      the blocknums and indices, put them in there and then
         //      do just one SetIntArrayRegion()
@@ -1581,7 +1532,6 @@
 
     jintArray array = env->NewIntArray(N);
     if (array == NULL) {
-        jniThrowException(env, "java/lang/OutOfMemoryError", "");
         res.unlockBag(startOfBag);
         return NULL;
     }
@@ -1590,7 +1540,7 @@
     const ResTable::bag_entry* bag = startOfBag;
     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
         value = bag->map.value;
-        
+
         // Take care of resolving the found resource to its final value.
         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
 #if THROW_ON_BAD_ID
@@ -1645,7 +1595,7 @@
     if (alloc.length() <= 0) {
         return NULL;
     }
-    
+
     jstring str = env->NewStringUTF(alloc.string());
     return str;
 }