• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* //device/libs/android_runtime/android_util_AssetManager.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 #define LOG_TAG "asset"
19 
20 #include <android_runtime/android_util_AssetManager.h>
21 
22 #include <inttypes.h>
23 #include <linux/capability.h>
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <sys/stat.h>
28 #include <sys/system_properties.h>
29 
30 #include <private/android_filesystem_config.h> // for AID_SYSTEM
31 
32 #include "androidfw/Asset.h"
33 #include "androidfw/AssetManager.h"
34 #include "androidfw/AttributeResolution.h"
35 #include "androidfw/ResourceTypes.h"
36 #include "android_runtime/AndroidRuntime.h"
37 #include "android_util_Binder.h"
38 #include "core_jni_helpers.h"
39 #include "jni.h"
40 #include <nativehelper/JNIHelp.h>
41 #include <nativehelper/ScopedStringChars.h>
42 #include <nativehelper/ScopedUtfChars.h>
43 #include "utils/Log.h"
44 #include "utils/misc.h"
45 #include "utils/String8.h"
46 
47 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
48 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
49 
50 
51 namespace android {
52 
53 static const bool kThrowOnBadId = false;
54 
55 // ----------------------------------------------------------------------------
56 
57 static struct typedvalue_offsets_t
58 {
59     jfieldID mType;
60     jfieldID mData;
61     jfieldID mString;
62     jfieldID mAssetCookie;
63     jfieldID mResourceId;
64     jfieldID mChangingConfigurations;
65     jfieldID mDensity;
66 } gTypedValueOffsets;
67 
68 static struct assetfiledescriptor_offsets_t
69 {
70     jfieldID mFd;
71     jfieldID mStartOffset;
72     jfieldID mLength;
73 } gAssetFileDescriptorOffsets;
74 
75 static struct assetmanager_offsets_t
76 {
77     jfieldID mObject;
78 } gAssetManagerOffsets;
79 
80 static struct sparsearray_offsets_t
81 {
82     jclass classObject;
83     jmethodID constructor;
84     jmethodID put;
85 } gSparseArrayOffsets;
86 
87 static struct configuration_offsets_t
88 {
89     jclass classObject;
90     jmethodID constructor;
91     jfieldID mSmallestScreenWidthDpOffset;
92     jfieldID mScreenWidthDpOffset;
93     jfieldID mScreenHeightDpOffset;
94 } gConfigurationOffsets;
95 
96 jclass g_stringClass = NULL;
97 
98 // ----------------------------------------------------------------------------
99 
100 static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
101                       const Res_value& value, uint32_t ref, ssize_t block,
102                       uint32_t typeSpecFlags, ResTable_config* config = NULL);
103 
copyValue(JNIEnv * env,jobject outValue,const ResTable * table,const Res_value & value,uint32_t ref,ssize_t block,uint32_t typeSpecFlags,ResTable_config * config)104 jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
105                const Res_value& value, uint32_t ref, ssize_t block,
106                uint32_t typeSpecFlags, ResTable_config* config)
107 {
108     env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
109     env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
110                      static_cast<jint>(table->getTableCookie(block)));
111     env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
112     env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
113     env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
114     env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
115             typeSpecFlags);
116     if (config != NULL) {
117         env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
118     }
119     return block;
120 }
121 
122 // This is called by zygote (running as user root) as part of preloadResources.
verifySystemIdmaps()123 static void verifySystemIdmaps()
124 {
125     pid_t pid;
126     char system_id[10];
127 
128     snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
129 
130     switch (pid = fork()) {
131         case -1:
132             ALOGE("failed to fork for idmap: %s", strerror(errno));
133             break;
134         case 0: // child
135             {
136                 struct __user_cap_header_struct capheader;
137                 struct __user_cap_data_struct capdata;
138 
139                 memset(&capheader, 0, sizeof(capheader));
140                 memset(&capdata, 0, sizeof(capdata));
141 
142                 capheader.version = _LINUX_CAPABILITY_VERSION;
143                 capheader.pid = 0;
144 
145                 if (capget(&capheader, &capdata) != 0) {
146                     ALOGE("capget: %s\n", strerror(errno));
147                     exit(1);
148                 }
149 
150                 capdata.effective = capdata.permitted;
151                 if (capset(&capheader, &capdata) != 0) {
152                     ALOGE("capset: %s\n", strerror(errno));
153                     exit(1);
154                 }
155 
156                 if (setgid(AID_SYSTEM) != 0) {
157                     ALOGE("setgid: %s\n", strerror(errno));
158                     exit(1);
159                 }
160 
161                 if (setuid(AID_SYSTEM) != 0) {
162                     ALOGE("setuid: %s\n", strerror(errno));
163                     exit(1);
164                 }
165 
166                 // Generic idmap parameters
167                 const char* argv[8];
168                 int argc = 0;
169                 struct stat st;
170 
171                 memset(argv, NULL, sizeof(argv));
172                 argv[argc++] = AssetManager::IDMAP_BIN;
173                 argv[argc++] = "--scan";
174                 argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
175                 argv[argc++] = AssetManager::TARGET_APK_PATH;
176                 argv[argc++] = AssetManager::IDMAP_DIR;
177 
178                 // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
179                 // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
180                 char subdir[PROP_VALUE_MAX];
181                 int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir);
182                 if (len > 0) {
183                     String8 overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
184                     if (stat(overlayPath.string(), &st) == 0) {
185                         argv[argc++] = overlayPath.string();
186                     }
187                 }
188                 if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
189                     argv[argc++] = AssetManager::OVERLAY_DIR;
190                 }
191 
192                 // Finally, invoke idmap (if any overlay directory exists)
193                 if (argc > 5) {
194                     execv(AssetManager::IDMAP_BIN, (char* const*)argv);
195                     ALOGE("failed to execv for idmap: %s", strerror(errno));
196                     exit(1); // should never get here
197                 } else {
198                     exit(0);
199                 }
200             }
201             break;
202         default: // parent
203             waitpid(pid, NULL, 0);
204             break;
205     }
206 }
207 
208 // ----------------------------------------------------------------------------
209 
210 // this guy is exported to other jni routines
assetManagerForJavaObject(JNIEnv * env,jobject obj)211 AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
212 {
213     jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
214     AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
215     if (am != NULL) {
216         return am;
217     }
218     jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
219     return NULL;
220 }
221 
android_content_AssetManager_openAsset(JNIEnv * env,jobject clazz,jstring fileName,jint mode)222 static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
223                                                 jstring fileName, jint mode)
224 {
225     AssetManager* am = assetManagerForJavaObject(env, clazz);
226     if (am == NULL) {
227         return 0;
228     }
229 
230     ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
231 
232     ScopedUtfChars fileName8(env, fileName);
233     if (fileName8.c_str() == NULL) {
234         jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
235         return -1;
236     }
237 
238     if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
239         && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
240         jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
241         return -1;
242     }
243 
244     Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
245 
246     if (a == NULL) {
247         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
248         return -1;
249     }
250 
251     //printf("Created Asset Stream: %p\n", a);
252 
253     return reinterpret_cast<jlong>(a);
254 }
255 
returnParcelFileDescriptor(JNIEnv * env,Asset * a,jlongArray outOffsets)256 static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
257 {
258     off64_t startOffset, length;
259     int fd = a->openFileDescriptor(&startOffset, &length);
260     delete a;
261 
262     if (fd < 0) {
263         jniThrowException(env, "java/io/FileNotFoundException",
264                 "This file can not be opened as a file descriptor; it is probably compressed");
265         return NULL;
266     }
267 
268     jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
269     if (offsets == NULL) {
270         close(fd);
271         return NULL;
272     }
273 
274     offsets[0] = startOffset;
275     offsets[1] = length;
276 
277     env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
278 
279     jobject fileDesc = jniCreateFileDescriptor(env, fd);
280     if (fileDesc == NULL) {
281         close(fd);
282         return NULL;
283     }
284 
285     return newParcelFileDescriptor(env, fileDesc);
286 }
287 
android_content_AssetManager_openAssetFd(JNIEnv * env,jobject clazz,jstring fileName,jlongArray outOffsets)288 static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
289                                                 jstring fileName, jlongArray outOffsets)
290 {
291     AssetManager* am = assetManagerForJavaObject(env, clazz);
292     if (am == NULL) {
293         return NULL;
294     }
295 
296     ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
297 
298     ScopedUtfChars fileName8(env, fileName);
299     if (fileName8.c_str() == NULL) {
300         return NULL;
301     }
302 
303     Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
304 
305     if (a == NULL) {
306         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
307         return NULL;
308     }
309 
310     //printf("Created Asset Stream: %p\n", a);
311 
312     return returnParcelFileDescriptor(env, a, outOffsets);
313 }
314 
android_content_AssetManager_openNonAssetNative(JNIEnv * env,jobject clazz,jint cookie,jstring fileName,jint mode)315 static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
316                                                          jint cookie,
317                                                          jstring fileName,
318                                                          jint mode)
319 {
320     AssetManager* am = assetManagerForJavaObject(env, clazz);
321     if (am == NULL) {
322         return 0;
323     }
324 
325     ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
326 
327     ScopedUtfChars fileName8(env, fileName);
328     if (fileName8.c_str() == NULL) {
329         return -1;
330     }
331 
332     if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
333         && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
334         jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
335         return -1;
336     }
337 
338     Asset* a = cookie
339         ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
340                 (Asset::AccessMode)mode)
341         : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
342 
343     if (a == NULL) {
344         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
345         return -1;
346     }
347 
348     //printf("Created Asset Stream: %p\n", a);
349 
350     return reinterpret_cast<jlong>(a);
351 }
352 
android_content_AssetManager_openNonAssetFdNative(JNIEnv * env,jobject clazz,jint cookie,jstring fileName,jlongArray outOffsets)353 static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
354                                                          jint cookie,
355                                                          jstring fileName,
356                                                          jlongArray outOffsets)
357 {
358     AssetManager* am = assetManagerForJavaObject(env, clazz);
359     if (am == NULL) {
360         return NULL;
361     }
362 
363     ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
364 
365     ScopedUtfChars fileName8(env, fileName);
366     if (fileName8.c_str() == NULL) {
367         return NULL;
368     }
369 
370     Asset* a = cookie
371         ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
372         : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
373 
374     if (a == NULL) {
375         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
376         return NULL;
377     }
378 
379     //printf("Created Asset Stream: %p\n", a);
380 
381     return returnParcelFileDescriptor(env, a, outOffsets);
382 }
383 
android_content_AssetManager_list(JNIEnv * env,jobject clazz,jstring fileName)384 static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
385                                                    jstring fileName)
386 {
387     AssetManager* am = assetManagerForJavaObject(env, clazz);
388     if (am == NULL) {
389         return NULL;
390     }
391 
392     ScopedUtfChars fileName8(env, fileName);
393     if (fileName8.c_str() == NULL) {
394         return NULL;
395     }
396 
397     AssetDir* dir = am->openDir(fileName8.c_str());
398 
399     if (dir == NULL) {
400         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
401         return NULL;
402     }
403 
404     size_t N = dir->getFileCount();
405 
406     jobjectArray array = env->NewObjectArray(dir->getFileCount(),
407                                                 g_stringClass, NULL);
408     if (array == NULL) {
409         delete dir;
410         return NULL;
411     }
412 
413     for (size_t i=0; i<N; i++) {
414         const String8& name = dir->getFileName(i);
415         jstring str = env->NewStringUTF(name.string());
416         if (str == NULL) {
417             delete dir;
418             return NULL;
419         }
420         env->SetObjectArrayElement(array, i, str);
421         env->DeleteLocalRef(str);
422     }
423 
424     delete dir;
425 
426     return array;
427 }
428 
android_content_AssetManager_destroyAsset(JNIEnv * env,jobject clazz,jlong assetHandle)429 static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
430                                                       jlong assetHandle)
431 {
432     Asset* a = reinterpret_cast<Asset*>(assetHandle);
433 
434     //printf("Destroying Asset Stream: %p\n", a);
435 
436     if (a == NULL) {
437         jniThrowNullPointerException(env, "asset");
438         return;
439     }
440 
441     delete a;
442 }
443 
android_content_AssetManager_readAssetChar(JNIEnv * env,jobject clazz,jlong assetHandle)444 static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
445                                                        jlong assetHandle)
446 {
447     Asset* a = reinterpret_cast<Asset*>(assetHandle);
448 
449     if (a == NULL) {
450         jniThrowNullPointerException(env, "asset");
451         return -1;
452     }
453 
454     uint8_t b;
455     ssize_t res = a->read(&b, 1);
456     return res == 1 ? b : -1;
457 }
458 
android_content_AssetManager_readAsset(JNIEnv * env,jobject clazz,jlong assetHandle,jbyteArray bArray,jint off,jint len)459 static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
460                                                 jlong assetHandle, jbyteArray bArray,
461                                                 jint off, jint len)
462 {
463     Asset* a = reinterpret_cast<Asset*>(assetHandle);
464 
465     if (a == NULL || bArray == NULL) {
466         jniThrowNullPointerException(env, "asset");
467         return -1;
468     }
469 
470     if (len == 0) {
471         return 0;
472     }
473 
474     jsize bLen = env->GetArrayLength(bArray);
475     if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
476         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
477         return -1;
478     }
479 
480     jbyte* b = env->GetByteArrayElements(bArray, NULL);
481     ssize_t res = a->read(b+off, len);
482     env->ReleaseByteArrayElements(bArray, b, 0);
483 
484     if (res > 0) return static_cast<jint>(res);
485 
486     if (res < 0) {
487         jniThrowException(env, "java/io/IOException", "");
488     }
489     return -1;
490 }
491 
android_content_AssetManager_seekAsset(JNIEnv * env,jobject clazz,jlong assetHandle,jlong offset,jint whence)492 static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
493                                                  jlong assetHandle,
494                                                  jlong offset, jint whence)
495 {
496     Asset* a = reinterpret_cast<Asset*>(assetHandle);
497 
498     if (a == NULL) {
499         jniThrowNullPointerException(env, "asset");
500         return -1;
501     }
502 
503     return a->seek(
504         offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
505 }
506 
android_content_AssetManager_getAssetLength(JNIEnv * env,jobject clazz,jlong assetHandle)507 static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
508                                                       jlong assetHandle)
509 {
510     Asset* a = reinterpret_cast<Asset*>(assetHandle);
511 
512     if (a == NULL) {
513         jniThrowNullPointerException(env, "asset");
514         return -1;
515     }
516 
517     return a->getLength();
518 }
519 
android_content_AssetManager_getAssetRemainingLength(JNIEnv * env,jobject clazz,jlong assetHandle)520 static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
521                                                                jlong assetHandle)
522 {
523     Asset* a = reinterpret_cast<Asset*>(assetHandle);
524 
525     if (a == NULL) {
526         jniThrowNullPointerException(env, "asset");
527         return -1;
528     }
529 
530     return a->getRemainingLength();
531 }
532 
android_content_AssetManager_addAssetPath(JNIEnv * env,jobject clazz,jstring path,jboolean appAsLib)533 static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
534                                                        jstring path, jboolean appAsLib)
535 {
536     ScopedUtfChars path8(env, path);
537     if (path8.c_str() == NULL) {
538         return 0;
539     }
540 
541     AssetManager* am = assetManagerForJavaObject(env, clazz);
542     if (am == NULL) {
543         return 0;
544     }
545 
546     int32_t cookie;
547     bool res = am->addAssetPath(String8(path8.c_str()), &cookie, appAsLib);
548 
549     return (res) ? static_cast<jint>(cookie) : 0;
550 }
551 
android_content_AssetManager_addOverlayPath(JNIEnv * env,jobject clazz,jstring idmapPath)552 static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
553                                                      jstring idmapPath)
554 {
555     ScopedUtfChars idmapPath8(env, idmapPath);
556     if (idmapPath8.c_str() == NULL) {
557         return 0;
558     }
559 
560     AssetManager* am = assetManagerForJavaObject(env, clazz);
561     if (am == NULL) {
562         return 0;
563     }
564 
565     int32_t cookie;
566     bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
567 
568     return (res) ? (jint)cookie : 0;
569 }
570 
android_content_AssetManager_isUpToDate(JNIEnv * env,jobject clazz)571 static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
572 {
573     AssetManager* am = assetManagerForJavaObject(env, clazz);
574     if (am == NULL) {
575         return JNI_TRUE;
576     }
577     return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
578 }
579 
getLocales(JNIEnv * env,jobject clazz,bool includeSystemLocales)580 static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales)
581 {
582     Vector<String8> locales;
583 
584     AssetManager* am = assetManagerForJavaObject(env, clazz);
585     if (am == NULL) {
586         return NULL;
587     }
588 
589     am->getLocales(&locales, includeSystemLocales);
590 
591     const int N = locales.size();
592 
593     jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
594     if (result == NULL) {
595         return NULL;
596     }
597 
598     for (int i=0; i<N; i++) {
599         jstring str = env->NewStringUTF(locales[i].string());
600         if (str == NULL) {
601             return NULL;
602         }
603         env->SetObjectArrayElement(result, i, str);
604         env->DeleteLocalRef(str);
605     }
606 
607     return result;
608 }
609 
android_content_AssetManager_getLocales(JNIEnv * env,jobject clazz)610 static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
611 {
612     return getLocales(env, clazz, true /* include system locales */);
613 }
614 
android_content_AssetManager_getNonSystemLocales(JNIEnv * env,jobject clazz)615 static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz)
616 {
617     return getLocales(env, clazz, false /* don't include system locales */);
618 }
619 
constructConfigurationObject(JNIEnv * env,const ResTable_config & config)620 static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
621     jobject result = env->NewObject(gConfigurationOffsets.classObject,
622             gConfigurationOffsets.constructor);
623     if (result == NULL) {
624         return NULL;
625     }
626 
627     env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
628             config.smallestScreenWidthDp);
629     env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
630     env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
631 
632     return result;
633 }
634 
getSizeConfigurationsInternal(JNIEnv * env,const Vector<ResTable_config> & configs)635 static jobjectArray getSizeConfigurationsInternal(JNIEnv* env,
636         const Vector<ResTable_config>& configs) {
637     const int N = configs.size();
638     jobjectArray result = env->NewObjectArray(N, gConfigurationOffsets.classObject, NULL);
639     if (result == NULL) {
640         return NULL;
641     }
642 
643     for (int i=0; i<N; i++) {
644         jobject config = constructConfigurationObject(env, configs[i]);
645         if (config == NULL) {
646             env->DeleteLocalRef(result);
647             return NULL;
648         }
649 
650         env->SetObjectArrayElement(result, i, config);
651         env->DeleteLocalRef(config);
652     }
653 
654     return result;
655 }
656 
android_content_AssetManager_getSizeConfigurations(JNIEnv * env,jobject clazz)657 static jobjectArray android_content_AssetManager_getSizeConfigurations(JNIEnv* env, jobject clazz) {
658     AssetManager* am = assetManagerForJavaObject(env, clazz);
659     if (am == NULL) {
660         return NULL;
661     }
662 
663     const ResTable& res(am->getResources());
664     Vector<ResTable_config> configs;
665     res.getConfigurations(&configs, false /* ignoreMipmap */, true /* ignoreAndroidPackage */);
666 
667     return getSizeConfigurationsInternal(env, configs);
668 }
669 
android_content_AssetManager_setConfiguration(JNIEnv * env,jobject clazz,jint mcc,jint mnc,jstring locale,jint orientation,jint touchscreen,jint density,jint keyboard,jint keyboardHidden,jint navigation,jint screenWidth,jint screenHeight,jint smallestScreenWidthDp,jint screenWidthDp,jint screenHeightDp,jint screenLayout,jint uiMode,jint colorMode,jint sdkVersion)670 static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
671                                                           jint mcc, jint mnc,
672                                                           jstring locale, jint orientation,
673                                                           jint touchscreen, jint density,
674                                                           jint keyboard, jint keyboardHidden,
675                                                           jint navigation,
676                                                           jint screenWidth, jint screenHeight,
677                                                           jint smallestScreenWidthDp,
678                                                           jint screenWidthDp, jint screenHeightDp,
679                                                           jint screenLayout, jint uiMode,
680                                                           jint colorMode, jint sdkVersion)
681 {
682     AssetManager* am = assetManagerForJavaObject(env, clazz);
683     if (am == NULL) {
684         return;
685     }
686 
687     ResTable_config config;
688     memset(&config, 0, sizeof(config));
689 
690     const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
691 
692     // Constants duplicated from Java class android.content.res.Configuration.
693     static const jint kScreenLayoutRoundMask = 0x300;
694     static const jint kScreenLayoutRoundShift = 8;
695 
696     config.mcc = (uint16_t)mcc;
697     config.mnc = (uint16_t)mnc;
698     config.orientation = (uint8_t)orientation;
699     config.touchscreen = (uint8_t)touchscreen;
700     config.density = (uint16_t)density;
701     config.keyboard = (uint8_t)keyboard;
702     config.inputFlags = (uint8_t)keyboardHidden;
703     config.navigation = (uint8_t)navigation;
704     config.screenWidth = (uint16_t)screenWidth;
705     config.screenHeight = (uint16_t)screenHeight;
706     config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
707     config.screenWidthDp = (uint16_t)screenWidthDp;
708     config.screenHeightDp = (uint16_t)screenHeightDp;
709     config.screenLayout = (uint8_t)screenLayout;
710     config.uiMode = (uint8_t)uiMode;
711     config.colorMode = (uint8_t)colorMode;
712     config.sdkVersion = (uint16_t)sdkVersion;
713     config.minorVersion = 0;
714 
715     // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
716     // in C++. We must extract the round qualifier out of the Java screenLayout and put it
717     // into screenLayout2.
718     config.screenLayout2 =
719             (uint8_t)((screenLayout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
720 
721     am->setConfiguration(config, locale8);
722 
723     if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
724 }
725 
android_content_AssetManager_getResourceIdentifier(JNIEnv * env,jobject clazz,jstring name,jstring defType,jstring defPackage)726 static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
727                                                             jstring name,
728                                                             jstring defType,
729                                                             jstring defPackage)
730 {
731     ScopedStringChars name16(env, name);
732     if (name16.get() == NULL) {
733         return 0;
734     }
735 
736     AssetManager* am = assetManagerForJavaObject(env, clazz);
737     if (am == NULL) {
738         return 0;
739     }
740 
741     const char16_t* defType16 = reinterpret_cast<const char16_t*>(defType)
742         ? reinterpret_cast<const char16_t*>(env->GetStringChars(defType, NULL))
743         : NULL;
744     jsize defTypeLen = defType
745         ? env->GetStringLength(defType) : 0;
746     const char16_t* defPackage16 = reinterpret_cast<const char16_t*>(defPackage)
747         ? reinterpret_cast<const char16_t*>(env->GetStringChars(defPackage,
748                                                                 NULL))
749         : NULL;
750     jsize defPackageLen = defPackage
751         ? env->GetStringLength(defPackage) : 0;
752 
753     jint ident = am->getResources().identifierForName(
754         reinterpret_cast<const char16_t*>(name16.get()), name16.size(),
755         defType16, defTypeLen, defPackage16, defPackageLen);
756 
757     if (defPackage16) {
758         env->ReleaseStringChars(defPackage,
759                                 reinterpret_cast<const jchar*>(defPackage16));
760     }
761     if (defType16) {
762         env->ReleaseStringChars(defType,
763                                 reinterpret_cast<const jchar*>(defType16));
764     }
765 
766     return ident;
767 }
768 
android_content_AssetManager_getResourceName(JNIEnv * env,jobject clazz,jint resid)769 static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
770                                                             jint resid)
771 {
772     AssetManager* am = assetManagerForJavaObject(env, clazz);
773     if (am == NULL) {
774         return NULL;
775     }
776 
777     ResTable::resource_name name;
778     if (!am->getResources().getResourceName(resid, true, &name)) {
779         return NULL;
780     }
781 
782     String16 str;
783     if (name.package != NULL) {
784         str.setTo(name.package, name.packageLen);
785     }
786     if (name.type8 != NULL || name.type != NULL) {
787         if (str.size() > 0) {
788             char16_t div = ':';
789             str.append(&div, 1);
790         }
791         if (name.type8 != NULL) {
792             str.append(String16(name.type8, name.typeLen));
793         } else {
794             str.append(name.type, name.typeLen);
795         }
796     }
797     if (name.name8 != NULL || name.name != NULL) {
798         if (str.size() > 0) {
799             char16_t div = '/';
800             str.append(&div, 1);
801         }
802         if (name.name8 != NULL) {
803             str.append(String16(name.name8, name.nameLen));
804         } else {
805             str.append(name.name, name.nameLen);
806         }
807     }
808 
809     return env->NewString((const jchar*)str.string(), str.size());
810 }
811 
android_content_AssetManager_getResourcePackageName(JNIEnv * env,jobject clazz,jint resid)812 static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
813                                                                    jint resid)
814 {
815     AssetManager* am = assetManagerForJavaObject(env, clazz);
816     if (am == NULL) {
817         return NULL;
818     }
819 
820     ResTable::resource_name name;
821     if (!am->getResources().getResourceName(resid, true, &name)) {
822         return NULL;
823     }
824 
825     if (name.package != NULL) {
826         return env->NewString((const jchar*)name.package, name.packageLen);
827     }
828 
829     return NULL;
830 }
831 
android_content_AssetManager_getResourceTypeName(JNIEnv * env,jobject clazz,jint resid)832 static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
833                                                                 jint resid)
834 {
835     AssetManager* am = assetManagerForJavaObject(env, clazz);
836     if (am == NULL) {
837         return NULL;
838     }
839 
840     ResTable::resource_name name;
841     if (!am->getResources().getResourceName(resid, true, &name)) {
842         return NULL;
843     }
844 
845     if (name.type8 != NULL) {
846         return env->NewStringUTF(name.type8);
847     }
848 
849     if (name.type != NULL) {
850         return env->NewString((const jchar*)name.type, name.typeLen);
851     }
852 
853     return NULL;
854 }
855 
android_content_AssetManager_getResourceEntryName(JNIEnv * env,jobject clazz,jint resid)856 static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
857                                                                  jint resid)
858 {
859     AssetManager* am = assetManagerForJavaObject(env, clazz);
860     if (am == NULL) {
861         return NULL;
862     }
863 
864     ResTable::resource_name name;
865     if (!am->getResources().getResourceName(resid, true, &name)) {
866         return NULL;
867     }
868 
869     if (name.name8 != NULL) {
870         return env->NewStringUTF(name.name8);
871     }
872 
873     if (name.name != NULL) {
874         return env->NewString((const jchar*)name.name, name.nameLen);
875     }
876 
877     return NULL;
878 }
879 
android_content_AssetManager_loadResourceValue(JNIEnv * env,jobject clazz,jint ident,jshort density,jobject outValue,jboolean resolve)880 static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
881                                                            jint ident,
882                                                            jshort density,
883                                                            jobject outValue,
884                                                            jboolean resolve)
885 {
886     if (outValue == NULL) {
887          jniThrowNullPointerException(env, "outValue");
888          return 0;
889     }
890     AssetManager* am = assetManagerForJavaObject(env, clazz);
891     if (am == NULL) {
892         return 0;
893     }
894     const ResTable& res(am->getResources());
895 
896     Res_value value;
897     ResTable_config config;
898     uint32_t typeSpecFlags;
899     ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
900     if (kThrowOnBadId) {
901         if (block == BAD_INDEX) {
902             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
903             return 0;
904         }
905     }
906     uint32_t ref = ident;
907     if (resolve) {
908         block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
909         if (kThrowOnBadId) {
910             if (block == BAD_INDEX) {
911                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
912                 return 0;
913             }
914         }
915     }
916     if (block >= 0) {
917         return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
918     }
919 
920     return static_cast<jint>(block);
921 }
922 
android_content_AssetManager_loadResourceBagValue(JNIEnv * env,jobject clazz,jint ident,jint bagEntryId,jobject outValue,jboolean resolve)923 static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
924                                                            jint ident, jint bagEntryId,
925                                                            jobject outValue, jboolean resolve)
926 {
927     AssetManager* am = assetManagerForJavaObject(env, clazz);
928     if (am == NULL) {
929         return 0;
930     }
931     const ResTable& res(am->getResources());
932 
933     // Now lock down the resource object and start pulling stuff from it.
934     res.lock();
935 
936     ssize_t block = -1;
937     Res_value value;
938 
939     const ResTable::bag_entry* entry = NULL;
940     uint32_t typeSpecFlags;
941     ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
942 
943     for (ssize_t i=0; i<entryCount; i++) {
944         if (((uint32_t)bagEntryId) == entry->map.name.ident) {
945             block = entry->stringBlock;
946             value = entry->map.value;
947         }
948         entry++;
949     }
950 
951     res.unlock();
952 
953     if (block < 0) {
954         return static_cast<jint>(block);
955     }
956 
957     uint32_t ref = ident;
958     if (resolve) {
959         block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
960         if (kThrowOnBadId) {
961             if (block == BAD_INDEX) {
962                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
963                 return 0;
964             }
965         }
966     }
967     if (block >= 0) {
968         return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
969     }
970 
971     return static_cast<jint>(block);
972 }
973 
android_content_AssetManager_getStringBlockCount(JNIEnv * env,jobject clazz)974 static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
975 {
976     AssetManager* am = assetManagerForJavaObject(env, clazz);
977     if (am == NULL) {
978         return 0;
979     }
980     return am->getResources().getTableCount();
981 }
982 
android_content_AssetManager_getNativeStringBlock(JNIEnv * env,jobject clazz,jint block)983 static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
984                                                            jint block)
985 {
986     AssetManager* am = assetManagerForJavaObject(env, clazz);
987     if (am == NULL) {
988         return 0;
989     }
990     return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
991 }
992 
android_content_AssetManager_getCookieName(JNIEnv * env,jobject clazz,jint cookie)993 static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
994                                                        jint cookie)
995 {
996     AssetManager* am = assetManagerForJavaObject(env, clazz);
997     if (am == NULL) {
998         return NULL;
999     }
1000     String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
1001     if (name.length() == 0) {
1002         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
1003         return NULL;
1004     }
1005     jstring str = env->NewStringUTF(name.string());
1006     return str;
1007 }
1008 
android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv * env,jobject clazz)1009 static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
1010 {
1011     AssetManager* am = assetManagerForJavaObject(env, clazz);
1012     if (am == NULL) {
1013         return 0;
1014     }
1015 
1016     const ResTable& res = am->getResources();
1017 
1018     jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
1019             gSparseArrayOffsets.constructor);
1020     const size_t N = res.getBasePackageCount();
1021     for (size_t i = 0; i < N; i++) {
1022         const String16 name = res.getBasePackageName(i);
1023         env->CallVoidMethod(
1024             sparseArray, gSparseArrayOffsets.put,
1025             static_cast<jint>(res.getBasePackageId(i)),
1026             env->NewString(reinterpret_cast<const jchar*>(name.string()),
1027                            name.size()));
1028     }
1029     return sparseArray;
1030 }
1031 
android_content_AssetManager_newTheme(JNIEnv * env,jobject clazz)1032 static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
1033 {
1034     AssetManager* am = assetManagerForJavaObject(env, clazz);
1035     if (am == NULL) {
1036         return 0;
1037     }
1038     return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
1039 }
1040 
android_content_AssetManager_deleteTheme(JNIEnv * env,jobject clazz,jlong themeHandle)1041 static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
1042                                                      jlong themeHandle)
1043 {
1044     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1045     delete theme;
1046 }
1047 
android_content_AssetManager_applyThemeStyle(JNIEnv * env,jobject clazz,jlong themeHandle,jint styleRes,jboolean force)1048 static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
1049                                                          jlong themeHandle,
1050                                                          jint styleRes,
1051                                                          jboolean force)
1052 {
1053     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1054     theme->applyStyle(styleRes, force ? true : false);
1055 }
1056 
android_content_AssetManager_copyTheme(JNIEnv * env,jobject clazz,jlong destHandle,jlong srcHandle)1057 static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
1058                                                    jlong destHandle, jlong srcHandle)
1059 {
1060     ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
1061     ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
1062     dest->setTo(*src);
1063 }
1064 
android_content_AssetManager_clearTheme(JNIEnv * env,jobject clazz,jlong themeHandle)1065 static void android_content_AssetManager_clearTheme(JNIEnv* env, jobject clazz, jlong themeHandle)
1066 {
1067     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1068     theme->clear();
1069 }
1070 
android_content_AssetManager_loadThemeAttributeValue(JNIEnv * env,jobject clazz,jlong themeHandle,jint ident,jobject outValue,jboolean resolve)1071 static jint android_content_AssetManager_loadThemeAttributeValue(
1072     JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
1073 {
1074     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1075     const ResTable& res(theme->getResTable());
1076 
1077     Res_value value;
1078     // XXX value could be different in different configs!
1079     uint32_t typeSpecFlags = 0;
1080     ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
1081     uint32_t ref = 0;
1082     if (resolve) {
1083         block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
1084         if (kThrowOnBadId) {
1085             if (block == BAD_INDEX) {
1086                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1087                 return 0;
1088             }
1089         }
1090     }
1091     return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
1092 }
1093 
android_content_AssetManager_getThemeChangingConfigurations(JNIEnv * env,jobject clazz,jlong themeHandle)1094 static jint android_content_AssetManager_getThemeChangingConfigurations(JNIEnv* env, jobject clazz,
1095                                                                         jlong themeHandle)
1096 {
1097     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1098     return theme->getChangingConfigurations();
1099 }
1100 
android_content_AssetManager_dumpTheme(JNIEnv * env,jobject clazz,jlong themeHandle,jint pri,jstring tag,jstring prefix)1101 static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
1102                                                    jlong themeHandle, jint pri,
1103                                                    jstring tag, jstring prefix)
1104 {
1105     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1106     const ResTable& res(theme->getResTable());
1107     (void)res;
1108 
1109     // XXX Need to use params.
1110     theme->dumpToLog();
1111 }
1112 
android_content_AssetManager_resolveAttrs(JNIEnv * env,jobject clazz,jlong themeToken,jint defStyleAttr,jint defStyleRes,jintArray inValues,jintArray attrs,jintArray outValues,jintArray outIndices)1113 static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
1114                                                           jlong themeToken,
1115                                                           jint defStyleAttr,
1116                                                           jint defStyleRes,
1117                                                           jintArray inValues,
1118                                                           jintArray attrs,
1119                                                           jintArray outValues,
1120                                                           jintArray outIndices)
1121 {
1122     if (themeToken == 0) {
1123         jniThrowNullPointerException(env, "theme token");
1124         return JNI_FALSE;
1125     }
1126     if (attrs == NULL) {
1127         jniThrowNullPointerException(env, "attrs");
1128         return JNI_FALSE;
1129     }
1130     if (outValues == NULL) {
1131         jniThrowNullPointerException(env, "out values");
1132         return JNI_FALSE;
1133     }
1134 
1135     const jsize NI = env->GetArrayLength(attrs);
1136     const jsize NV = env->GetArrayLength(outValues);
1137     if (NV < (NI*STYLE_NUM_ENTRIES)) {
1138         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1139         return JNI_FALSE;
1140     }
1141 
1142     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1143     if (src == NULL) {
1144         return JNI_FALSE;
1145     }
1146 
1147     jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
1148     const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
1149 
1150     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1151     if (baseDest == NULL) {
1152         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1153         return JNI_FALSE;
1154     }
1155 
1156     jint* indices = NULL;
1157     if (outIndices != NULL) {
1158         if (env->GetArrayLength(outIndices) > NI) {
1159             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1160         }
1161     }
1162 
1163     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1164     bool result = ResolveAttrs(theme, defStyleAttr, defStyleRes,
1165                                (uint32_t*) srcValues, NSV,
1166                                (uint32_t*) src, NI,
1167                                (uint32_t*) baseDest,
1168                                (uint32_t*) indices);
1169 
1170     if (indices != NULL) {
1171         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1172     }
1173     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1174     env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
1175     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1176     return result ? JNI_TRUE : JNI_FALSE;
1177 }
1178 
android_content_AssetManager_applyStyle(JNIEnv * env,jobject,jlong themeToken,jint defStyleAttr,jint defStyleRes,jlong xmlParserToken,jintArray attrsObj,jint length,jlong outValuesAddress,jlong outIndicesAddress)1179 static void android_content_AssetManager_applyStyle(JNIEnv* env, jobject, jlong themeToken,
1180         jint defStyleAttr, jint defStyleRes, jlong xmlParserToken, jintArray attrsObj, jint length,
1181         jlong outValuesAddress, jlong outIndicesAddress) {
1182     jint* attrs = env->GetIntArrayElements(attrsObj, 0);
1183     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1184     ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
1185     uint32_t* outValues = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outValuesAddress));
1186     uint32_t* outIndices = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outIndicesAddress));
1187     ApplyStyle(theme, xmlParser, defStyleAttr, defStyleRes,
1188             reinterpret_cast<const uint32_t*>(attrs), length, outValues, outIndices);
1189     env->ReleaseIntArrayElements(attrsObj, attrs, JNI_ABORT);
1190 }
1191 
android_content_AssetManager_retrieveAttributes(JNIEnv * env,jobject clazz,jlong xmlParserToken,jintArray attrs,jintArray outValues,jintArray outIndices)1192 static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1193                                                         jlong xmlParserToken,
1194                                                         jintArray attrs,
1195                                                         jintArray outValues,
1196                                                         jintArray outIndices)
1197 {
1198     if (xmlParserToken == 0) {
1199         jniThrowNullPointerException(env, "xmlParserToken");
1200         return JNI_FALSE;
1201     }
1202     if (attrs == NULL) {
1203         jniThrowNullPointerException(env, "attrs");
1204         return JNI_FALSE;
1205     }
1206     if (outValues == NULL) {
1207         jniThrowNullPointerException(env, "out values");
1208         return JNI_FALSE;
1209     }
1210 
1211     AssetManager* am = assetManagerForJavaObject(env, clazz);
1212     if (am == NULL) {
1213         return JNI_FALSE;
1214     }
1215     const ResTable& res(am->getResources());
1216     ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
1217 
1218     const jsize NI = env->GetArrayLength(attrs);
1219     const jsize NV = env->GetArrayLength(outValues);
1220     if (NV < (NI*STYLE_NUM_ENTRIES)) {
1221         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1222         return JNI_FALSE;
1223     }
1224 
1225     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1226     if (src == NULL) {
1227         return JNI_FALSE;
1228     }
1229 
1230     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1231     if (baseDest == NULL) {
1232         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1233         return JNI_FALSE;
1234     }
1235 
1236     jint* indices = NULL;
1237     if (outIndices != NULL) {
1238         if (env->GetArrayLength(outIndices) > NI) {
1239             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1240         }
1241     }
1242 
1243     bool result = RetrieveAttributes(&res, xmlParser,
1244                                      (uint32_t*) src, NI,
1245                                      (uint32_t*) baseDest,
1246                                      (uint32_t*) indices);
1247 
1248     if (indices != NULL) {
1249         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1250     }
1251     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1252     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1253     return result ? JNI_TRUE : JNI_FALSE;
1254 }
1255 
android_content_AssetManager_getArraySize(JNIEnv * env,jobject clazz,jint id)1256 static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1257                                                        jint id)
1258 {
1259     AssetManager* am = assetManagerForJavaObject(env, clazz);
1260     if (am == NULL) {
1261         return 0;
1262     }
1263     const ResTable& res(am->getResources());
1264 
1265     res.lock();
1266     const ResTable::bag_entry* defStyleEnt = NULL;
1267     ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1268     res.unlock();
1269 
1270     return static_cast<jint>(bagOff);
1271 }
1272 
android_content_AssetManager_retrieveArray(JNIEnv * env,jobject clazz,jint id,jintArray outValues)1273 static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1274                                                         jint id,
1275                                                         jintArray outValues)
1276 {
1277     if (outValues == NULL) {
1278         jniThrowNullPointerException(env, "out values");
1279         return JNI_FALSE;
1280     }
1281 
1282     AssetManager* am = assetManagerForJavaObject(env, clazz);
1283     if (am == NULL) {
1284         return JNI_FALSE;
1285     }
1286     const ResTable& res(am->getResources());
1287     ResTable_config config;
1288     Res_value value;
1289     ssize_t block;
1290 
1291     const jsize NV = env->GetArrayLength(outValues);
1292 
1293     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1294     jint* dest = baseDest;
1295     if (dest == NULL) {
1296         jniThrowException(env, "java/lang/OutOfMemoryError", "");
1297         return JNI_FALSE;
1298     }
1299 
1300     // Now lock down the resource object and start pulling stuff from it.
1301     res.lock();
1302 
1303     const ResTable::bag_entry* arrayEnt = NULL;
1304     uint32_t arrayTypeSetFlags = 0;
1305     ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1306     const ResTable::bag_entry* endArrayEnt = arrayEnt +
1307         (bagOff >= 0 ? bagOff : 0);
1308 
1309     int i = 0;
1310     uint32_t typeSetFlags;
1311     while (i < NV && arrayEnt < endArrayEnt) {
1312         block = arrayEnt->stringBlock;
1313         typeSetFlags = arrayTypeSetFlags;
1314         config.density = 0;
1315         value = arrayEnt->map.value;
1316 
1317         uint32_t resid = 0;
1318         if (value.dataType != Res_value::TYPE_NULL) {
1319             // Take care of resolving the found resource to its final value.
1320             //printf("Resolving attribute reference\n");
1321             ssize_t newBlock = res.resolveReference(&value, block, &resid,
1322                     &typeSetFlags, &config);
1323             if (kThrowOnBadId) {
1324                 if (newBlock == BAD_INDEX) {
1325                     jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1326                     return JNI_FALSE;
1327                 }
1328             }
1329             if (newBlock >= 0) block = newBlock;
1330         }
1331 
1332         // Deal with the special @null value -- it turns back to TYPE_NULL.
1333         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1334             value.dataType = Res_value::TYPE_NULL;
1335             value.data = Res_value::DATA_NULL_UNDEFINED;
1336         }
1337 
1338         //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1339 
1340         // Write the final value back to Java.
1341         dest[STYLE_TYPE] = value.dataType;
1342         dest[STYLE_DATA] = value.data;
1343         dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
1344         dest[STYLE_RESOURCE_ID] = resid;
1345         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1346         dest[STYLE_DENSITY] = config.density;
1347         dest += STYLE_NUM_ENTRIES;
1348         i+= STYLE_NUM_ENTRIES;
1349         arrayEnt++;
1350     }
1351 
1352     i /= STYLE_NUM_ENTRIES;
1353 
1354     res.unlock();
1355 
1356     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1357 
1358     return i;
1359 }
1360 
android_content_AssetManager_openXmlAssetNative(JNIEnv * env,jobject clazz,jint cookie,jstring fileName)1361 static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1362                                                          jint cookie,
1363                                                          jstring fileName)
1364 {
1365     AssetManager* am = assetManagerForJavaObject(env, clazz);
1366     if (am == NULL) {
1367         return 0;
1368     }
1369 
1370     ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1371 
1372     ScopedUtfChars fileName8(env, fileName);
1373     if (fileName8.c_str() == NULL) {
1374         return 0;
1375     }
1376 
1377     int32_t assetCookie = static_cast<int32_t>(cookie);
1378     Asset* a = assetCookie
1379         ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1380         : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
1381 
1382     if (a == NULL) {
1383         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
1384         return 0;
1385     }
1386 
1387     const DynamicRefTable* dynamicRefTable =
1388             am->getResources().getDynamicRefTableForCookie(assetCookie);
1389     ResXMLTree* block = new ResXMLTree(dynamicRefTable);
1390     status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1391     a->close();
1392     delete a;
1393 
1394     if (err != NO_ERROR) {
1395         jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
1396         return 0;
1397     }
1398 
1399     return reinterpret_cast<jlong>(block);
1400 }
1401 
android_content_AssetManager_getArrayStringInfo(JNIEnv * env,jobject clazz,jint arrayResId)1402 static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1403                                                                  jint arrayResId)
1404 {
1405     AssetManager* am = assetManagerForJavaObject(env, clazz);
1406     if (am == NULL) {
1407         return NULL;
1408     }
1409     const ResTable& res(am->getResources());
1410 
1411     const ResTable::bag_entry* startOfBag;
1412     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1413     if (N < 0) {
1414         return NULL;
1415     }
1416 
1417     jintArray array = env->NewIntArray(N * 2);
1418     if (array == NULL) {
1419         res.unlockBag(startOfBag);
1420         return NULL;
1421     }
1422 
1423     Res_value value;
1424     const ResTable::bag_entry* bag = startOfBag;
1425     for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1426         jint stringIndex = -1;
1427         jint stringBlock = 0;
1428         value = bag->map.value;
1429 
1430         // Take care of resolving the found resource to its final value.
1431         stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1432         if (value.dataType == Res_value::TYPE_STRING) {
1433             stringIndex = value.data;
1434         }
1435 
1436         if (kThrowOnBadId) {
1437             if (stringBlock == BAD_INDEX) {
1438                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1439                 return array;
1440             }
1441         }
1442 
1443         //todo: It might be faster to allocate a C array to contain
1444         //      the blocknums and indices, put them in there and then
1445         //      do just one SetIntArrayRegion()
1446         env->SetIntArrayRegion(array, j, 1, &stringBlock);
1447         env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1448         j = j + 2;
1449     }
1450     res.unlockBag(startOfBag);
1451     return array;
1452 }
1453 
android_content_AssetManager_getArrayStringResource(JNIEnv * env,jobject clazz,jint arrayResId)1454 static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1455                                                                         jint arrayResId)
1456 {
1457     AssetManager* am = assetManagerForJavaObject(env, clazz);
1458     if (am == NULL) {
1459         return NULL;
1460     }
1461     const ResTable& res(am->getResources());
1462 
1463     const ResTable::bag_entry* startOfBag;
1464     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1465     if (N < 0) {
1466         return NULL;
1467     }
1468 
1469     jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
1470     if (env->ExceptionCheck()) {
1471         res.unlockBag(startOfBag);
1472         return NULL;
1473     }
1474 
1475     Res_value value;
1476     const ResTable::bag_entry* bag = startOfBag;
1477     size_t strLen = 0;
1478     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1479         value = bag->map.value;
1480         jstring str = NULL;
1481 
1482         // Take care of resolving the found resource to its final value.
1483         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1484         if (kThrowOnBadId) {
1485             if (block == BAD_INDEX) {
1486                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1487                 return array;
1488             }
1489         }
1490         if (value.dataType == Res_value::TYPE_STRING) {
1491             const ResStringPool* pool = res.getTableStringBlock(block);
1492             const char* str8 = pool->string8At(value.data, &strLen);
1493             if (str8 != NULL) {
1494                 str = env->NewStringUTF(str8);
1495             } else {
1496                 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1497                 str = env->NewString(reinterpret_cast<const jchar*>(str16),
1498                                      strLen);
1499             }
1500 
1501             // If one of our NewString{UTF} calls failed due to memory, an
1502             // exception will be pending.
1503             if (env->ExceptionCheck()) {
1504                 res.unlockBag(startOfBag);
1505                 return NULL;
1506             }
1507 
1508             env->SetObjectArrayElement(array, i, str);
1509 
1510             // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1511             // If we have a large amount of strings in our array, we might
1512             // overflow the local reference table of the VM.
1513             env->DeleteLocalRef(str);
1514         }
1515     }
1516     res.unlockBag(startOfBag);
1517     return array;
1518 }
1519 
android_content_AssetManager_getArrayIntResource(JNIEnv * env,jobject clazz,jint arrayResId)1520 static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1521                                                                         jint arrayResId)
1522 {
1523     AssetManager* am = assetManagerForJavaObject(env, clazz);
1524     if (am == NULL) {
1525         return NULL;
1526     }
1527     const ResTable& res(am->getResources());
1528 
1529     const ResTable::bag_entry* startOfBag;
1530     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1531     if (N < 0) {
1532         return NULL;
1533     }
1534 
1535     jintArray array = env->NewIntArray(N);
1536     if (array == NULL) {
1537         res.unlockBag(startOfBag);
1538         return NULL;
1539     }
1540 
1541     Res_value value;
1542     const ResTable::bag_entry* bag = startOfBag;
1543     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1544         value = bag->map.value;
1545 
1546         // Take care of resolving the found resource to its final value.
1547         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1548         if (kThrowOnBadId) {
1549             if (block == BAD_INDEX) {
1550                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1551                 return array;
1552             }
1553         }
1554         if (value.dataType >= Res_value::TYPE_FIRST_INT
1555                 && value.dataType <= Res_value::TYPE_LAST_INT) {
1556             int intVal = value.data;
1557             env->SetIntArrayRegion(array, i, 1, &intVal);
1558         }
1559     }
1560     res.unlockBag(startOfBag);
1561     return array;
1562 }
1563 
android_content_AssetManager_getStyleAttributes(JNIEnv * env,jobject clazz,jint styleId)1564 static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
1565                                                                  jint styleId)
1566 {
1567     AssetManager* am = assetManagerForJavaObject(env, clazz);
1568     if (am == NULL) {
1569         return NULL;
1570     }
1571     const ResTable& res(am->getResources());
1572 
1573     const ResTable::bag_entry* startOfBag;
1574     const ssize_t N = res.lockBag(styleId, &startOfBag);
1575     if (N < 0) {
1576         return NULL;
1577     }
1578 
1579     jintArray array = env->NewIntArray(N);
1580     if (array == NULL) {
1581         res.unlockBag(startOfBag);
1582         return NULL;
1583     }
1584 
1585     const ResTable::bag_entry* bag = startOfBag;
1586     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1587         int resourceId = bag->map.name.ident;
1588         env->SetIntArrayRegion(array, i, 1, &resourceId);
1589     }
1590     res.unlockBag(startOfBag);
1591     return array;
1592 }
1593 
android_content_AssetManager_init(JNIEnv * env,jobject clazz,jboolean isSystem)1594 static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
1595 {
1596     if (isSystem) {
1597         verifySystemIdmaps();
1598     }
1599     AssetManager* am = new AssetManager();
1600     if (am == NULL) {
1601         jniThrowException(env, "java/lang/OutOfMemoryError", "");
1602         return;
1603     }
1604 
1605     am->addDefaultAssets();
1606 
1607     ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1608     env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
1609 }
1610 
android_content_AssetManager_destroy(JNIEnv * env,jobject clazz)1611 static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1612 {
1613     AssetManager* am = (AssetManager*)
1614         (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
1615     ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
1616     if (am != NULL) {
1617         delete am;
1618         env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
1619     }
1620 }
1621 
android_content_AssetManager_getGlobalAssetCount(JNIEnv * env,jobject clazz)1622 static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1623 {
1624     return Asset::getGlobalCount();
1625 }
1626 
android_content_AssetManager_getAssetAllocations(JNIEnv * env,jobject clazz)1627 static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1628 {
1629     String8 alloc = Asset::getAssetAllocations();
1630     if (alloc.length() <= 0) {
1631         return NULL;
1632     }
1633 
1634     jstring str = env->NewStringUTF(alloc.string());
1635     return str;
1636 }
1637 
android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv * env,jobject clazz)1638 static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1639 {
1640     return AssetManager::getGlobalCount();
1641 }
1642 
1643 // ----------------------------------------------------------------------------
1644 
1645 /*
1646  * JNI registration.
1647  */
1648 static const JNINativeMethod gAssetManagerMethods[] = {
1649     /* name, signature, funcPtr */
1650 
1651     // Basic asset stuff.
1652     { "openAsset",      "(Ljava/lang/String;I)J",
1653         (void*) android_content_AssetManager_openAsset },
1654     { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1655         (void*) android_content_AssetManager_openAssetFd },
1656     { "openNonAssetNative", "(ILjava/lang/String;I)J",
1657         (void*) android_content_AssetManager_openNonAssetNative },
1658     { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1659         (void*) android_content_AssetManager_openNonAssetFdNative },
1660     { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
1661         (void*) android_content_AssetManager_list },
1662     { "destroyAsset",   "(J)V",
1663         (void*) android_content_AssetManager_destroyAsset },
1664     { "readAssetChar",  "(J)I",
1665         (void*) android_content_AssetManager_readAssetChar },
1666     { "readAsset",      "(J[BII)I",
1667         (void*) android_content_AssetManager_readAsset },
1668     { "seekAsset",      "(JJI)J",
1669         (void*) android_content_AssetManager_seekAsset },
1670     { "getAssetLength", "(J)J",
1671         (void*) android_content_AssetManager_getAssetLength },
1672     { "getAssetRemainingLength", "(J)J",
1673         (void*) android_content_AssetManager_getAssetRemainingLength },
1674     { "addAssetPathNative", "(Ljava/lang/String;Z)I",
1675         (void*) android_content_AssetManager_addAssetPath },
1676     { "addOverlayPathNative",   "(Ljava/lang/String;)I",
1677         (void*) android_content_AssetManager_addOverlayPath },
1678     { "isUpToDate",     "()Z",
1679         (void*) android_content_AssetManager_isUpToDate },
1680 
1681     // Resources.
1682     { "getLocales",      "()[Ljava/lang/String;",
1683         (void*) android_content_AssetManager_getLocales },
1684     { "getNonSystemLocales", "()[Ljava/lang/String;",
1685         (void*) android_content_AssetManager_getNonSystemLocales },
1686     { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
1687         (void*) android_content_AssetManager_getSizeConfigurations },
1688     { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIIII)V",
1689         (void*) android_content_AssetManager_setConfiguration },
1690     { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1691         (void*) android_content_AssetManager_getResourceIdentifier },
1692     { "getResourceName","(I)Ljava/lang/String;",
1693         (void*) android_content_AssetManager_getResourceName },
1694     { "getResourcePackageName","(I)Ljava/lang/String;",
1695         (void*) android_content_AssetManager_getResourcePackageName },
1696     { "getResourceTypeName","(I)Ljava/lang/String;",
1697         (void*) android_content_AssetManager_getResourceTypeName },
1698     { "getResourceEntryName","(I)Ljava/lang/String;",
1699         (void*) android_content_AssetManager_getResourceEntryName },
1700     { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
1701         (void*) android_content_AssetManager_loadResourceValue },
1702     { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1703         (void*) android_content_AssetManager_loadResourceBagValue },
1704     { "getStringBlockCount","()I",
1705         (void*) android_content_AssetManager_getStringBlockCount },
1706     { "getNativeStringBlock","(I)J",
1707         (void*) android_content_AssetManager_getNativeStringBlock },
1708     { "getCookieName","(I)Ljava/lang/String;",
1709         (void*) android_content_AssetManager_getCookieName },
1710     { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
1711         (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
1712 
1713     // Themes.
1714     { "newTheme", "()J",
1715         (void*) android_content_AssetManager_newTheme },
1716     { "deleteTheme", "(J)V",
1717         (void*) android_content_AssetManager_deleteTheme },
1718     { "applyThemeStyle", "(JIZ)V",
1719         (void*) android_content_AssetManager_applyThemeStyle },
1720     { "copyTheme", "(JJ)V",
1721         (void*) android_content_AssetManager_copyTheme },
1722     { "clearTheme", "(J)V",
1723         (void*) android_content_AssetManager_clearTheme },
1724     { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
1725         (void*) android_content_AssetManager_loadThemeAttributeValue },
1726     { "getThemeChangingConfigurations", "(J)I",
1727         (void*) android_content_AssetManager_getThemeChangingConfigurations },
1728     { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
1729         (void*) android_content_AssetManager_dumpTheme },
1730     { "applyStyle","(JIIJ[IIJJ)V",
1731         (void*) android_content_AssetManager_applyStyle },
1732     { "resolveAttrs","(JII[I[I[I[I)Z",
1733         (void*) android_content_AssetManager_resolveAttrs },
1734     { "retrieveAttributes","(J[I[I[I)Z",
1735         (void*) android_content_AssetManager_retrieveAttributes },
1736     { "getArraySize","(I)I",
1737         (void*) android_content_AssetManager_getArraySize },
1738     { "retrieveArray","(I[I)I",
1739         (void*) android_content_AssetManager_retrieveArray },
1740 
1741     // XML files.
1742     { "openXmlAssetNative", "(ILjava/lang/String;)J",
1743         (void*) android_content_AssetManager_openXmlAssetNative },
1744 
1745     // Arrays.
1746     { "getArrayStringResource","(I)[Ljava/lang/String;",
1747         (void*) android_content_AssetManager_getArrayStringResource },
1748     { "getArrayStringInfo","(I)[I",
1749         (void*) android_content_AssetManager_getArrayStringInfo },
1750     { "getArrayIntResource","(I)[I",
1751         (void*) android_content_AssetManager_getArrayIntResource },
1752     { "getStyleAttributes","(I)[I",
1753         (void*) android_content_AssetManager_getStyleAttributes },
1754 
1755     // Bookkeeping.
1756     { "init",           "(Z)V",
1757         (void*) android_content_AssetManager_init },
1758     { "destroy",        "()V",
1759         (void*) android_content_AssetManager_destroy },
1760     { "getGlobalAssetCount", "()I",
1761         (void*) android_content_AssetManager_getGlobalAssetCount },
1762     { "getAssetAllocations", "()Ljava/lang/String;",
1763         (void*) android_content_AssetManager_getAssetAllocations },
1764     { "getGlobalAssetManagerCount", "()I",
1765         (void*) android_content_AssetManager_getGlobalAssetManagerCount },
1766 };
1767 
register_android_content_AssetManager(JNIEnv * env)1768 int register_android_content_AssetManager(JNIEnv* env)
1769 {
1770     jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
1771     gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
1772     gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
1773     gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
1774                                                  "Ljava/lang/CharSequence;");
1775     gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
1776     gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
1777     gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
1778                                                                  "changingConfigurations", "I");
1779     gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
1780 
1781     jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
1782     gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
1783                                                       "Landroid/os/ParcelFileDescriptor;");
1784     gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
1785     gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
1786 
1787     jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
1788     gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
1789 
1790     jclass stringClass = FindClassOrDie(env, "java/lang/String");
1791     g_stringClass = MakeGlobalRefOrDie(env, stringClass);
1792 
1793     jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
1794     gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
1795     gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
1796                                                        "<init>", "()V");
1797     gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
1798                                                "(ILjava/lang/Object;)V");
1799 
1800     jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
1801     gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
1802     gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass,
1803             "<init>", "()V");
1804     gConfigurationOffsets.mSmallestScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
1805             "smallestScreenWidthDp", "I");
1806     gConfigurationOffsets.mScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
1807             "screenWidthDp", "I");
1808     gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass,
1809             "screenHeightDp", "I");
1810 
1811     return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
1812                                 NELEM(gAssetManagerMethods));
1813 }
1814 
1815 }; // namespace android
1816