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