• 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 
29 #include <private/android_filesystem_config.h> // for AID_SYSTEM
30 
31 #include "androidfw/Asset.h"
32 #include "androidfw/AssetManager.h"
33 #include "androidfw/AttributeFinder.h"
34 #include "androidfw/ResourceTypes.h"
35 #include "android_runtime/AndroidRuntime.h"
36 #include "android_util_Binder.h"
37 #include "core_jni_helpers.h"
38 #include "jni.h"
39 #include "JNIHelp.h"
40 #include "ScopedStringChars.h"
41 #include "ScopedUtfChars.h"
42 #include "utils/Log.h"
43 #include "utils/misc.h"
44 
45 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
46 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
47 
48 
49 namespace android {
50 
51 static const bool kThrowOnBadId = false;
52 static const bool kDebugStyles = false;
53 
54 // ----------------------------------------------------------------------------
55 
56 static struct typedvalue_offsets_t
57 {
58     jfieldID mType;
59     jfieldID mData;
60     jfieldID mString;
61     jfieldID mAssetCookie;
62     jfieldID mResourceId;
63     jfieldID mChangingConfigurations;
64     jfieldID mDensity;
65 } gTypedValueOffsets;
66 
67 static struct assetfiledescriptor_offsets_t
68 {
69     jfieldID mFd;
70     jfieldID mStartOffset;
71     jfieldID mLength;
72 } gAssetFileDescriptorOffsets;
73 
74 static struct assetmanager_offsets_t
75 {
76     jfieldID mObject;
77 } gAssetManagerOffsets;
78 
79 static struct sparsearray_offsets_t
80 {
81     jclass classObject;
82     jmethodID constructor;
83     jmethodID put;
84 } gSparseArrayOffsets;
85 
86 static struct configuration_offsets_t
87 {
88     jclass classObject;
89     jmethodID constructor;
90     jfieldID mSmallestScreenWidthDpOffset;
91     jfieldID mScreenWidthDpOffset;
92     jfieldID mScreenHeightDpOffset;
93 } gConfigurationOffsets;
94 
95 jclass g_stringClass = NULL;
96 
97 // ----------------------------------------------------------------------------
98 
99 enum {
100     STYLE_NUM_ENTRIES = 6,
101     STYLE_TYPE = 0,
102     STYLE_DATA = 1,
103     STYLE_ASSET_COOKIE = 2,
104     STYLE_RESOURCE_ID = 3,
105     STYLE_CHANGING_CONFIGURATIONS = 4,
106     STYLE_DENSITY = 5
107 };
108 
109 static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
110                       const Res_value& value, uint32_t ref, ssize_t block,
111                       uint32_t typeSpecFlags, ResTable_config* config = NULL);
112 
copyValue(JNIEnv * env,jobject outValue,const ResTable * table,const Res_value & value,uint32_t ref,ssize_t block,uint32_t typeSpecFlags,ResTable_config * config)113 jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
114                const Res_value& value, uint32_t ref, ssize_t block,
115                uint32_t typeSpecFlags, ResTable_config* config)
116 {
117     env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
118     env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
119                      static_cast<jint>(table->getTableCookie(block)));
120     env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
121     env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
122     env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
123     env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
124             typeSpecFlags);
125     if (config != NULL) {
126         env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
127     }
128     return block;
129 }
130 
131 // This is called by zygote (running as user root) as part of preloadResources.
verifySystemIdmaps()132 static void verifySystemIdmaps()
133 {
134     pid_t pid;
135     char system_id[10];
136 
137     snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
138 
139     switch (pid = fork()) {
140         case -1:
141             ALOGE("failed to fork for idmap: %s", strerror(errno));
142             break;
143         case 0: // child
144             {
145                 struct __user_cap_header_struct capheader;
146                 struct __user_cap_data_struct capdata;
147 
148                 memset(&capheader, 0, sizeof(capheader));
149                 memset(&capdata, 0, sizeof(capdata));
150 
151                 capheader.version = _LINUX_CAPABILITY_VERSION;
152                 capheader.pid = 0;
153 
154                 if (capget(&capheader, &capdata) != 0) {
155                     ALOGE("capget: %s\n", strerror(errno));
156                     exit(1);
157                 }
158 
159                 capdata.effective = capdata.permitted;
160                 if (capset(&capheader, &capdata) != 0) {
161                     ALOGE("capset: %s\n", strerror(errno));
162                     exit(1);
163                 }
164 
165                 if (setgid(AID_SYSTEM) != 0) {
166                     ALOGE("setgid: %s\n", strerror(errno));
167                     exit(1);
168                 }
169 
170                 if (setuid(AID_SYSTEM) != 0) {
171                     ALOGE("setuid: %s\n", strerror(errno));
172                     exit(1);
173                 }
174 
175                 // Generic idmap parameters
176                 const char* argv[7];
177                 int argc = 0;
178                 struct stat st;
179 
180                 memset(argv, NULL, sizeof(argv));
181                 argv[argc++] = AssetManager::IDMAP_BIN;
182                 argv[argc++] = "--scan";
183                 argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
184                 argv[argc++] = AssetManager::TARGET_APK_PATH;
185                 argv[argc++] = AssetManager::IDMAP_DIR;
186 
187                 // Directories to scan for overlays
188                 // /vendor/overlay
189                 if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
190                     argv[argc++] = AssetManager::OVERLAY_DIR;
191                  }
192 
193                 // Finally, invoke idmap (if any overlay directory exists)
194                 if (argc > 5) {
195                     execv(AssetManager::IDMAP_BIN, (char* const*)argv);
196                     ALOGE("failed to execl for idmap: %s", strerror(errno));
197                     exit(1); // should never get here
198                 } else {
199                     exit(0);
200                 }
201             }
202             break;
203         default: // parent
204             waitpid(pid, NULL, 0);
205             break;
206     }
207 }
208 
209 // ----------------------------------------------------------------------------
210 
211 // this guy is exported to other jni routines
assetManagerForJavaObject(JNIEnv * env,jobject obj)212 AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
213 {
214     jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
215     AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
216     if (am != NULL) {
217         return am;
218     }
219     jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
220     return NULL;
221 }
222 
android_content_AssetManager_openAsset(JNIEnv * env,jobject clazz,jstring fileName,jint mode)223 static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
224                                                 jstring fileName, jint mode)
225 {
226     AssetManager* am = assetManagerForJavaObject(env, clazz);
227     if (am == NULL) {
228         return 0;
229     }
230 
231     ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
232 
233     ScopedUtfChars fileName8(env, fileName);
234     if (fileName8.c_str() == NULL) {
235         jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
236         return -1;
237     }
238 
239     if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
240         && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
241         jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
242         return -1;
243     }
244 
245     Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
246 
247     if (a == NULL) {
248         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
249         return -1;
250     }
251 
252     //printf("Created Asset Stream: %p\n", a);
253 
254     return reinterpret_cast<jlong>(a);
255 }
256 
returnParcelFileDescriptor(JNIEnv * env,Asset * a,jlongArray outOffsets)257 static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
258 {
259     off64_t startOffset, length;
260     int fd = a->openFileDescriptor(&startOffset, &length);
261     delete a;
262 
263     if (fd < 0) {
264         jniThrowException(env, "java/io/FileNotFoundException",
265                 "This file can not be opened as a file descriptor; it is probably compressed");
266         return NULL;
267     }
268 
269     jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
270     if (offsets == NULL) {
271         close(fd);
272         return NULL;
273     }
274 
275     offsets[0] = startOffset;
276     offsets[1] = length;
277 
278     env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
279 
280     jobject fileDesc = jniCreateFileDescriptor(env, fd);
281     if (fileDesc == NULL) {
282         close(fd);
283         return NULL;
284     }
285 
286     return newParcelFileDescriptor(env, fileDesc);
287 }
288 
android_content_AssetManager_openAssetFd(JNIEnv * env,jobject clazz,jstring fileName,jlongArray outOffsets)289 static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
290                                                 jstring fileName, jlongArray outOffsets)
291 {
292     AssetManager* am = assetManagerForJavaObject(env, clazz);
293     if (am == NULL) {
294         return NULL;
295     }
296 
297     ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
298 
299     ScopedUtfChars fileName8(env, fileName);
300     if (fileName8.c_str() == NULL) {
301         return NULL;
302     }
303 
304     Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
305 
306     if (a == NULL) {
307         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
308         return NULL;
309     }
310 
311     //printf("Created Asset Stream: %p\n", a);
312 
313     return returnParcelFileDescriptor(env, a, outOffsets);
314 }
315 
android_content_AssetManager_openNonAssetNative(JNIEnv * env,jobject clazz,jint cookie,jstring fileName,jint mode)316 static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
317                                                          jint cookie,
318                                                          jstring fileName,
319                                                          jint mode)
320 {
321     AssetManager* am = assetManagerForJavaObject(env, clazz);
322     if (am == NULL) {
323         return 0;
324     }
325 
326     ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
327 
328     ScopedUtfChars fileName8(env, fileName);
329     if (fileName8.c_str() == NULL) {
330         return -1;
331     }
332 
333     if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
334         && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
335         jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
336         return -1;
337     }
338 
339     Asset* a = cookie
340         ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
341                 (Asset::AccessMode)mode)
342         : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
343 
344     if (a == NULL) {
345         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
346         return -1;
347     }
348 
349     //printf("Created Asset Stream: %p\n", a);
350 
351     return reinterpret_cast<jlong>(a);
352 }
353 
android_content_AssetManager_openNonAssetFdNative(JNIEnv * env,jobject clazz,jint cookie,jstring fileName,jlongArray outOffsets)354 static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
355                                                          jint cookie,
356                                                          jstring fileName,
357                                                          jlongArray outOffsets)
358 {
359     AssetManager* am = assetManagerForJavaObject(env, clazz);
360     if (am == NULL) {
361         return NULL;
362     }
363 
364     ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
365 
366     ScopedUtfChars fileName8(env, fileName);
367     if (fileName8.c_str() == NULL) {
368         return NULL;
369     }
370 
371     Asset* a = cookie
372         ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
373         : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
374 
375     if (a == NULL) {
376         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
377         return NULL;
378     }
379 
380     //printf("Created Asset Stream: %p\n", a);
381 
382     return returnParcelFileDescriptor(env, a, outOffsets);
383 }
384 
android_content_AssetManager_list(JNIEnv * env,jobject clazz,jstring fileName)385 static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
386                                                    jstring fileName)
387 {
388     AssetManager* am = assetManagerForJavaObject(env, clazz);
389     if (am == NULL) {
390         return NULL;
391     }
392 
393     ScopedUtfChars fileName8(env, fileName);
394     if (fileName8.c_str() == NULL) {
395         return NULL;
396     }
397 
398     AssetDir* dir = am->openDir(fileName8.c_str());
399 
400     if (dir == NULL) {
401         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
402         return NULL;
403     }
404 
405     size_t N = dir->getFileCount();
406 
407     jobjectArray array = env->NewObjectArray(dir->getFileCount(),
408                                                 g_stringClass, NULL);
409     if (array == NULL) {
410         delete dir;
411         return NULL;
412     }
413 
414     for (size_t i=0; i<N; i++) {
415         const String8& name = dir->getFileName(i);
416         jstring str = env->NewStringUTF(name.string());
417         if (str == NULL) {
418             delete dir;
419             return NULL;
420         }
421         env->SetObjectArrayElement(array, i, str);
422         env->DeleteLocalRef(str);
423     }
424 
425     delete dir;
426 
427     return array;
428 }
429 
android_content_AssetManager_destroyAsset(JNIEnv * env,jobject clazz,jlong assetHandle)430 static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
431                                                       jlong assetHandle)
432 {
433     Asset* a = reinterpret_cast<Asset*>(assetHandle);
434 
435     //printf("Destroying Asset Stream: %p\n", a);
436 
437     if (a == NULL) {
438         jniThrowNullPointerException(env, "asset");
439         return;
440     }
441 
442     delete a;
443 }
444 
android_content_AssetManager_readAssetChar(JNIEnv * env,jobject clazz,jlong assetHandle)445 static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
446                                                        jlong assetHandle)
447 {
448     Asset* a = reinterpret_cast<Asset*>(assetHandle);
449 
450     if (a == NULL) {
451         jniThrowNullPointerException(env, "asset");
452         return -1;
453     }
454 
455     uint8_t b;
456     ssize_t res = a->read(&b, 1);
457     return res == 1 ? b : -1;
458 }
459 
android_content_AssetManager_readAsset(JNIEnv * env,jobject clazz,jlong assetHandle,jbyteArray bArray,jint off,jint len)460 static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
461                                                 jlong assetHandle, jbyteArray bArray,
462                                                 jint off, jint len)
463 {
464     Asset* a = reinterpret_cast<Asset*>(assetHandle);
465 
466     if (a == NULL || bArray == NULL) {
467         jniThrowNullPointerException(env, "asset");
468         return -1;
469     }
470 
471     if (len == 0) {
472         return 0;
473     }
474 
475     jsize bLen = env->GetArrayLength(bArray);
476     if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
477         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
478         return -1;
479     }
480 
481     jbyte* b = env->GetByteArrayElements(bArray, NULL);
482     ssize_t res = a->read(b+off, len);
483     env->ReleaseByteArrayElements(bArray, b, 0);
484 
485     if (res > 0) return static_cast<jint>(res);
486 
487     if (res < 0) {
488         jniThrowException(env, "java/io/IOException", "");
489     }
490     return -1;
491 }
492 
android_content_AssetManager_seekAsset(JNIEnv * env,jobject clazz,jlong assetHandle,jlong offset,jint whence)493 static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
494                                                  jlong assetHandle,
495                                                  jlong offset, jint whence)
496 {
497     Asset* a = reinterpret_cast<Asset*>(assetHandle);
498 
499     if (a == NULL) {
500         jniThrowNullPointerException(env, "asset");
501         return -1;
502     }
503 
504     return a->seek(
505         offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
506 }
507 
android_content_AssetManager_getAssetLength(JNIEnv * env,jobject clazz,jlong assetHandle)508 static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
509                                                       jlong assetHandle)
510 {
511     Asset* a = reinterpret_cast<Asset*>(assetHandle);
512 
513     if (a == NULL) {
514         jniThrowNullPointerException(env, "asset");
515         return -1;
516     }
517 
518     return a->getLength();
519 }
520 
android_content_AssetManager_getAssetRemainingLength(JNIEnv * env,jobject clazz,jlong assetHandle)521 static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
522                                                                jlong assetHandle)
523 {
524     Asset* a = reinterpret_cast<Asset*>(assetHandle);
525 
526     if (a == NULL) {
527         jniThrowNullPointerException(env, "asset");
528         return -1;
529     }
530 
531     return a->getRemainingLength();
532 }
533 
android_content_AssetManager_addAssetPath(JNIEnv * env,jobject clazz,jstring path,jboolean appAsLib)534 static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
535                                                        jstring path, jboolean appAsLib)
536 {
537     ScopedUtfChars path8(env, path);
538     if (path8.c_str() == NULL) {
539         return 0;
540     }
541 
542     AssetManager* am = assetManagerForJavaObject(env, clazz);
543     if (am == NULL) {
544         return 0;
545     }
546 
547     int32_t cookie;
548     bool res = am->addAssetPath(String8(path8.c_str()), &cookie, appAsLib);
549 
550     return (res) ? static_cast<jint>(cookie) : 0;
551 }
552 
android_content_AssetManager_addOverlayPath(JNIEnv * env,jobject clazz,jstring idmapPath)553 static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
554                                                      jstring idmapPath)
555 {
556     ScopedUtfChars idmapPath8(env, idmapPath);
557     if (idmapPath8.c_str() == NULL) {
558         return 0;
559     }
560 
561     AssetManager* am = assetManagerForJavaObject(env, clazz);
562     if (am == NULL) {
563         return 0;
564     }
565 
566     int32_t cookie;
567     bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
568 
569     return (res) ? (jint)cookie : 0;
570 }
571 
android_content_AssetManager_isUpToDate(JNIEnv * env,jobject clazz)572 static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
573 {
574     AssetManager* am = assetManagerForJavaObject(env, clazz);
575     if (am == NULL) {
576         return JNI_TRUE;
577     }
578     return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
579 }
580 
getLocales(JNIEnv * env,jobject clazz,bool includeSystemLocales)581 static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales)
582 {
583     Vector<String8> locales;
584 
585     AssetManager* am = assetManagerForJavaObject(env, clazz);
586     if (am == NULL) {
587         return NULL;
588     }
589 
590     am->getLocales(&locales, includeSystemLocales);
591 
592     const int N = locales.size();
593 
594     jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
595     if (result == NULL) {
596         return NULL;
597     }
598 
599     for (int i=0; i<N; i++) {
600         jstring str = env->NewStringUTF(locales[i].string());
601         if (str == NULL) {
602             return NULL;
603         }
604         env->SetObjectArrayElement(result, i, str);
605         env->DeleteLocalRef(str);
606     }
607 
608     return result;
609 }
610 
android_content_AssetManager_getLocales(JNIEnv * env,jobject clazz)611 static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
612 {
613     return getLocales(env, clazz, true /* include system locales */);
614 }
615 
android_content_AssetManager_getNonSystemLocales(JNIEnv * env,jobject clazz)616 static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz)
617 {
618     return getLocales(env, clazz, false /* don't include system locales */);
619 }
620 
constructConfigurationObject(JNIEnv * env,const ResTable_config & config)621 static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
622     jobject result = env->NewObject(gConfigurationOffsets.classObject,
623             gConfigurationOffsets.constructor);
624     if (result == NULL) {
625         return NULL;
626     }
627 
628     env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
629             config.smallestScreenWidthDp);
630     env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
631     env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
632 
633     return result;
634 }
635 
getSizeConfigurationsInternal(JNIEnv * env,const Vector<ResTable_config> & configs)636 static jobjectArray getSizeConfigurationsInternal(JNIEnv* env,
637         const Vector<ResTable_config>& configs) {
638     const int N = configs.size();
639     jobjectArray result = env->NewObjectArray(N, gConfigurationOffsets.classObject, NULL);
640     if (result == NULL) {
641         return NULL;
642     }
643 
644     for (int i=0; i<N; i++) {
645         jobject config = constructConfigurationObject(env, configs[i]);
646         if (config == NULL) {
647             env->DeleteLocalRef(result);
648             return NULL;
649         }
650 
651         env->SetObjectArrayElement(result, i, config);
652         env->DeleteLocalRef(config);
653     }
654 
655     return result;
656 }
657 
android_content_AssetManager_getSizeConfigurations(JNIEnv * env,jobject clazz)658 static jobjectArray android_content_AssetManager_getSizeConfigurations(JNIEnv* env, jobject clazz) {
659     AssetManager* am = assetManagerForJavaObject(env, clazz);
660     if (am == NULL) {
661         return NULL;
662     }
663 
664     const ResTable& res(am->getResources());
665     Vector<ResTable_config> configs;
666     res.getConfigurations(&configs, false /* ignoreMipmap */, true /* ignoreAndroidPackage */);
667 
668     return getSizeConfigurationsInternal(env, configs);
669 }
670 
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 sdkVersion)671 static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
672                                                           jint mcc, jint mnc,
673                                                           jstring locale, jint orientation,
674                                                           jint touchscreen, jint density,
675                                                           jint keyboard, jint keyboardHidden,
676                                                           jint navigation,
677                                                           jint screenWidth, jint screenHeight,
678                                                           jint smallestScreenWidthDp,
679                                                           jint screenWidthDp, jint screenHeightDp,
680                                                           jint screenLayout, jint uiMode,
681                                                           jint sdkVersion)
682 {
683     AssetManager* am = assetManagerForJavaObject(env, clazz);
684     if (am == NULL) {
685         return;
686     }
687 
688     ResTable_config config;
689     memset(&config, 0, sizeof(config));
690 
691     const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
692 
693     // Constants duplicated from Java class android.content.res.Configuration.
694     static const jint kScreenLayoutRoundMask = 0x300;
695     static const jint kScreenLayoutRoundShift = 8;
696 
697     config.mcc = (uint16_t)mcc;
698     config.mnc = (uint16_t)mnc;
699     config.orientation = (uint8_t)orientation;
700     config.touchscreen = (uint8_t)touchscreen;
701     config.density = (uint16_t)density;
702     config.keyboard = (uint8_t)keyboard;
703     config.inputFlags = (uint8_t)keyboardHidden;
704     config.navigation = (uint8_t)navigation;
705     config.screenWidth = (uint16_t)screenWidth;
706     config.screenHeight = (uint16_t)screenHeight;
707     config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
708     config.screenWidthDp = (uint16_t)screenWidthDp;
709     config.screenHeightDp = (uint16_t)screenHeightDp;
710     config.screenLayout = (uint8_t)screenLayout;
711     config.uiMode = (uint8_t)uiMode;
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 
1113 class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
1114 public:
XmlAttributeFinder(const ResXMLParser * parser)1115     XmlAttributeFinder(const ResXMLParser* parser)
1116         : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0)
1117         , mParser(parser) {}
1118 
getAttribute(jsize index) const1119     inline uint32_t getAttribute(jsize index) const {
1120         return mParser->getAttributeNameResID(index);
1121     }
1122 
1123 private:
1124     const ResXMLParser* mParser;
1125 };
1126 
1127 class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
1128 public:
BagAttributeFinder(const ResTable::bag_entry * start,const ResTable::bag_entry * end)1129     BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
1130         : BackTrackingAttributeFinder(start, end) {}
1131 
getAttribute(const ResTable::bag_entry * entry) const1132     inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
1133         return entry->map.name.ident;
1134     }
1135 };
1136 
android_content_AssetManager_resolveAttrs(JNIEnv * env,jobject clazz,jlong themeToken,jint defStyleAttr,jint defStyleRes,jintArray inValues,jintArray attrs,jintArray outValues,jintArray outIndices)1137 static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
1138                                                           jlong themeToken,
1139                                                           jint defStyleAttr,
1140                                                           jint defStyleRes,
1141                                                           jintArray inValues,
1142                                                           jintArray attrs,
1143                                                           jintArray outValues,
1144                                                           jintArray outIndices)
1145 {
1146     if (themeToken == 0) {
1147         jniThrowNullPointerException(env, "theme token");
1148         return JNI_FALSE;
1149     }
1150     if (attrs == NULL) {
1151         jniThrowNullPointerException(env, "attrs");
1152         return JNI_FALSE;
1153     }
1154     if (outValues == NULL) {
1155         jniThrowNullPointerException(env, "out values");
1156         return JNI_FALSE;
1157     }
1158 
1159     if (kDebugStyles) {
1160         ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x "
1161               "defStyleRes=0x%x", themeToken, defStyleAttr, defStyleRes);
1162     }
1163 
1164     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1165     const ResTable& res = theme->getResTable();
1166     ResTable_config config;
1167     Res_value value;
1168 
1169     const jsize NI = env->GetArrayLength(attrs);
1170     const jsize NV = env->GetArrayLength(outValues);
1171     if (NV < (NI*STYLE_NUM_ENTRIES)) {
1172         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1173         return JNI_FALSE;
1174     }
1175 
1176     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1177     if (src == NULL) {
1178         return JNI_FALSE;
1179     }
1180 
1181     jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
1182     const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
1183 
1184     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1185     jint* dest = baseDest;
1186     if (dest == NULL) {
1187         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1188         return JNI_FALSE;
1189     }
1190 
1191     jint* indices = NULL;
1192     int indicesIdx = 0;
1193     if (outIndices != NULL) {
1194         if (env->GetArrayLength(outIndices) > NI) {
1195             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1196         }
1197     }
1198 
1199     // Load default style from attribute, if specified...
1200     uint32_t defStyleBagTypeSetFlags = 0;
1201     if (defStyleAttr != 0) {
1202         Res_value value;
1203         if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1204             if (value.dataType == Res_value::TYPE_REFERENCE) {
1205                 defStyleRes = value.data;
1206             }
1207         }
1208     }
1209 
1210     // Now lock down the resource object and start pulling stuff from it.
1211     res.lock();
1212 
1213     // Retrieve the default style bag, if requested.
1214     const ResTable::bag_entry* defStyleStart = NULL;
1215     uint32_t defStyleTypeSetFlags = 0;
1216     ssize_t bagOff = defStyleRes != 0
1217             ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
1218     defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1219     const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
1220     BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
1221 
1222     // Now iterate through all of the attributes that the client has requested,
1223     // filling in each with whatever data we can find.
1224     ssize_t block = 0;
1225     uint32_t typeSetFlags;
1226     for (jsize ii=0; ii<NI; ii++) {
1227         const uint32_t curIdent = (uint32_t)src[ii];
1228 
1229         if (kDebugStyles) {
1230             ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1231         }
1232 
1233         // Try to find a value for this attribute...  we prioritize values
1234         // coming from, first XML attributes, then XML style, then default
1235         // style, and finally the theme.
1236         value.dataType = Res_value::TYPE_NULL;
1237         value.data = Res_value::DATA_NULL_UNDEFINED;
1238         typeSetFlags = 0;
1239         config.density = 0;
1240 
1241         // Retrieve the current input value if available.
1242         if (NSV > 0 && srcValues[ii] != 0) {
1243             block = -1;
1244             value.dataType = Res_value::TYPE_ATTRIBUTE;
1245             value.data = srcValues[ii];
1246             if (kDebugStyles) {
1247                 ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
1248             }
1249         }
1250 
1251         if (value.dataType == Res_value::TYPE_NULL) {
1252             const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent);
1253             if (defStyleEntry != defStyleEnd) {
1254                 block = defStyleEntry->stringBlock;
1255                 typeSetFlags = defStyleTypeSetFlags;
1256                 value = defStyleEntry->map.value;
1257                 if (kDebugStyles) {
1258                     ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1259                 }
1260             }
1261         }
1262 
1263         uint32_t resid = 0;
1264         if (value.dataType != Res_value::TYPE_NULL) {
1265             // Take care of resolving the found resource to its final value.
1266             ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1267                     &resid, &typeSetFlags, &config);
1268             if (newBlock >= 0) block = newBlock;
1269             if (kDebugStyles) {
1270                 ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1271             }
1272         } else {
1273             // If we still don't have a value for this attribute, try to find
1274             // it in the theme!
1275             ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1276             if (newBlock >= 0) {
1277                 if (kDebugStyles) {
1278                     ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1279                 }
1280                 newBlock = res.resolveReference(&value, block, &resid,
1281                         &typeSetFlags, &config);
1282                 if (kThrowOnBadId) {
1283                     if (newBlock == BAD_INDEX) {
1284                         jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1285                         return JNI_FALSE;
1286                     }
1287                 }
1288                 if (newBlock >= 0) block = newBlock;
1289                 if (kDebugStyles) {
1290                     ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1291                 }
1292             }
1293         }
1294 
1295         // Deal with the special @null value -- it turns back to TYPE_NULL.
1296         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1297             if (kDebugStyles) {
1298                 ALOGI("-> Setting to @null!");
1299             }
1300             value.dataType = Res_value::TYPE_NULL;
1301             value.data = Res_value::DATA_NULL_UNDEFINED;
1302             block = -1;
1303         }
1304 
1305         if (kDebugStyles) {
1306             ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType,
1307                   value.data);
1308         }
1309 
1310         // Write the final value back to Java.
1311         dest[STYLE_TYPE] = value.dataType;
1312         dest[STYLE_DATA] = value.data;
1313         dest[STYLE_ASSET_COOKIE] =
1314             block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1315         dest[STYLE_RESOURCE_ID] = resid;
1316         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1317         dest[STYLE_DENSITY] = config.density;
1318 
1319         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1320             indicesIdx++;
1321             indices[indicesIdx] = ii;
1322         }
1323 
1324         dest += STYLE_NUM_ENTRIES;
1325     }
1326 
1327     res.unlock();
1328 
1329     if (indices != NULL) {
1330         indices[0] = indicesIdx;
1331         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1332     }
1333     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1334     env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
1335     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1336 
1337     return JNI_TRUE;
1338 }
1339 
android_content_AssetManager_applyStyle(JNIEnv * env,jobject clazz,jlong themeToken,jint defStyleAttr,jint defStyleRes,jlong xmlParserToken,jintArray attrs,jintArray outValues,jintArray outIndices)1340 static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
1341                                                         jlong themeToken,
1342                                                         jint defStyleAttr,
1343                                                         jint defStyleRes,
1344                                                         jlong xmlParserToken,
1345                                                         jintArray attrs,
1346                                                         jintArray outValues,
1347                                                         jintArray outIndices)
1348 {
1349     if (themeToken == 0) {
1350         jniThrowNullPointerException(env, "theme token");
1351         return JNI_FALSE;
1352     }
1353     if (attrs == NULL) {
1354         jniThrowNullPointerException(env, "attrs");
1355         return JNI_FALSE;
1356     }
1357     if (outValues == NULL) {
1358         jniThrowNullPointerException(env, "out values");
1359         return JNI_FALSE;
1360     }
1361 
1362     if (kDebugStyles) {
1363     ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x defStyleRes=0x%x "
1364           "xml=0x%" PRIx64, themeToken, defStyleAttr, defStyleRes,
1365           xmlParserToken);
1366     }
1367 
1368     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1369     const ResTable& res = theme->getResTable();
1370     ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
1371     ResTable_config config;
1372     Res_value value;
1373 
1374     const jsize NI = env->GetArrayLength(attrs);
1375     const jsize NV = env->GetArrayLength(outValues);
1376     if (NV < (NI*STYLE_NUM_ENTRIES)) {
1377         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1378         return JNI_FALSE;
1379     }
1380 
1381     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1382     if (src == NULL) {
1383         return JNI_FALSE;
1384     }
1385 
1386     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1387     jint* dest = baseDest;
1388     if (dest == NULL) {
1389         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1390         return JNI_FALSE;
1391     }
1392 
1393     jint* indices = NULL;
1394     int indicesIdx = 0;
1395     if (outIndices != NULL) {
1396         if (env->GetArrayLength(outIndices) > NI) {
1397             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1398         }
1399     }
1400 
1401     // Load default style from attribute, if specified...
1402     uint32_t defStyleBagTypeSetFlags = 0;
1403     if (defStyleAttr != 0) {
1404         Res_value value;
1405         if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1406             if (value.dataType == Res_value::TYPE_REFERENCE) {
1407                 defStyleRes = value.data;
1408             }
1409         }
1410     }
1411 
1412     // Retrieve the style class associated with the current XML tag.
1413     int style = 0;
1414     uint32_t styleBagTypeSetFlags = 0;
1415     if (xmlParser != NULL) {
1416         ssize_t idx = xmlParser->indexOfStyle();
1417         if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
1418             if (value.dataType == value.TYPE_ATTRIBUTE) {
1419                 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
1420                     value.dataType = Res_value::TYPE_NULL;
1421                 }
1422             }
1423             if (value.dataType == value.TYPE_REFERENCE) {
1424                 style = value.data;
1425             }
1426         }
1427     }
1428 
1429     // Now lock down the resource object and start pulling stuff from it.
1430     res.lock();
1431 
1432     // Retrieve the default style bag, if requested.
1433     const ResTable::bag_entry* defStyleAttrStart = NULL;
1434     uint32_t defStyleTypeSetFlags = 0;
1435     ssize_t bagOff = defStyleRes != 0
1436             ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
1437     defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1438     const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
1439     BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
1440 
1441     // Retrieve the style class bag, if requested.
1442     const ResTable::bag_entry* styleAttrStart = NULL;
1443     uint32_t styleTypeSetFlags = 0;
1444     bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
1445     styleTypeSetFlags |= styleBagTypeSetFlags;
1446     const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
1447     BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
1448 
1449     // Retrieve the XML attributes, if requested.
1450     static const ssize_t kXmlBlock = 0x10000000;
1451     XmlAttributeFinder xmlAttrFinder(xmlParser);
1452     const jsize xmlAttrEnd = xmlParser != NULL ? xmlParser->getAttributeCount() : 0;
1453 
1454     // Now iterate through all of the attributes that the client has requested,
1455     // filling in each with whatever data we can find.
1456     ssize_t block = 0;
1457     uint32_t typeSetFlags;
1458     for (jsize ii = 0; ii < NI; ii++) {
1459         const uint32_t curIdent = (uint32_t)src[ii];
1460 
1461         if (kDebugStyles) {
1462             ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1463         }
1464 
1465         // Try to find a value for this attribute...  we prioritize values
1466         // coming from, first XML attributes, then XML style, then default
1467         // style, and finally the theme.
1468         value.dataType = Res_value::TYPE_NULL;
1469         value.data = Res_value::DATA_NULL_UNDEFINED;
1470         typeSetFlags = 0;
1471         config.density = 0;
1472 
1473         // Walk through the xml attributes looking for the requested attribute.
1474         const jsize xmlAttrIdx = xmlAttrFinder.find(curIdent);
1475         if (xmlAttrIdx != xmlAttrEnd) {
1476             // We found the attribute we were looking for.
1477             block = kXmlBlock;
1478             xmlParser->getAttributeValue(xmlAttrIdx, &value);
1479             if (kDebugStyles) {
1480                 ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
1481             }
1482         }
1483 
1484         if (value.dataType == Res_value::TYPE_NULL) {
1485             // Walk through the style class values looking for the requested attribute.
1486             const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent);
1487             if (styleAttrEntry != styleAttrEnd) {
1488                 // We found the attribute we were looking for.
1489                 block = styleAttrEntry->stringBlock;
1490                 typeSetFlags = styleTypeSetFlags;
1491                 value = styleAttrEntry->map.value;
1492                 if (kDebugStyles) {
1493                     ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
1494                 }
1495             }
1496         }
1497 
1498         if (value.dataType == Res_value::TYPE_NULL) {
1499             // Walk through the default style values looking for the requested attribute.
1500             const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
1501             if (defStyleAttrEntry != defStyleAttrEnd) {
1502                 // We found the attribute we were looking for.
1503                 block = defStyleAttrEntry->stringBlock;
1504                 typeSetFlags = styleTypeSetFlags;
1505                 value = defStyleAttrEntry->map.value;
1506                 if (kDebugStyles) {
1507                     ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1508                 }
1509             }
1510         }
1511 
1512         uint32_t resid = 0;
1513         if (value.dataType != Res_value::TYPE_NULL) {
1514             // Take care of resolving the found resource to its final value.
1515             ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1516                     &resid, &typeSetFlags, &config);
1517             if (newBlock >= 0) {
1518                 block = newBlock;
1519             }
1520 
1521             if (kDebugStyles) {
1522                 ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1523             }
1524         } else {
1525             // If we still don't have a value for this attribute, try to find
1526             // it in the theme!
1527             ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1528             if (newBlock >= 0) {
1529                 if (kDebugStyles) {
1530                     ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1531                 }
1532                 newBlock = res.resolveReference(&value, block, &resid,
1533                         &typeSetFlags, &config);
1534                 if (kThrowOnBadId) {
1535                     if (newBlock == BAD_INDEX) {
1536                         jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1537                         return JNI_FALSE;
1538                     }
1539                 }
1540 
1541                 if (newBlock >= 0) {
1542                     block = newBlock;
1543                 }
1544 
1545                 if (kDebugStyles) {
1546                     ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1547                 }
1548             }
1549         }
1550 
1551         // Deal with the special @null value -- it turns back to TYPE_NULL.
1552         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1553             if (kDebugStyles) {
1554                 ALOGI("-> Setting to @null!");
1555             }
1556             value.dataType = Res_value::TYPE_NULL;
1557             value.data = Res_value::DATA_NULL_UNDEFINED;
1558             block = kXmlBlock;
1559         }
1560 
1561         if (kDebugStyles) {
1562             ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data);
1563         }
1564 
1565         // Write the final value back to Java.
1566         dest[STYLE_TYPE] = value.dataType;
1567         dest[STYLE_DATA] = value.data;
1568         dest[STYLE_ASSET_COOKIE] = block != kXmlBlock ?
1569             static_cast<jint>(res.getTableCookie(block)) : -1;
1570         dest[STYLE_RESOURCE_ID] = resid;
1571         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1572         dest[STYLE_DENSITY] = config.density;
1573 
1574         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1575             indicesIdx++;
1576             indices[indicesIdx] = ii;
1577         }
1578 
1579         dest += STYLE_NUM_ENTRIES;
1580     }
1581 
1582     res.unlock();
1583 
1584     if (indices != NULL) {
1585         indices[0] = indicesIdx;
1586         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1587     }
1588     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1589     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1590 
1591     return JNI_TRUE;
1592 }
1593 
android_content_AssetManager_retrieveAttributes(JNIEnv * env,jobject clazz,jlong xmlParserToken,jintArray attrs,jintArray outValues,jintArray outIndices)1594 static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1595                                                         jlong xmlParserToken,
1596                                                         jintArray attrs,
1597                                                         jintArray outValues,
1598                                                         jintArray outIndices)
1599 {
1600     if (xmlParserToken == 0) {
1601         jniThrowNullPointerException(env, "xmlParserToken");
1602         return JNI_FALSE;
1603     }
1604     if (attrs == NULL) {
1605         jniThrowNullPointerException(env, "attrs");
1606         return JNI_FALSE;
1607     }
1608     if (outValues == NULL) {
1609         jniThrowNullPointerException(env, "out values");
1610         return JNI_FALSE;
1611     }
1612 
1613     AssetManager* am = assetManagerForJavaObject(env, clazz);
1614     if (am == NULL) {
1615         return JNI_FALSE;
1616     }
1617     const ResTable& res(am->getResources());
1618     ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
1619     ResTable_config config;
1620     Res_value value;
1621 
1622     const jsize NI = env->GetArrayLength(attrs);
1623     const jsize NV = env->GetArrayLength(outValues);
1624     if (NV < (NI*STYLE_NUM_ENTRIES)) {
1625         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1626         return JNI_FALSE;
1627     }
1628 
1629     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1630     if (src == NULL) {
1631         return JNI_FALSE;
1632     }
1633 
1634     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1635     jint* dest = baseDest;
1636     if (dest == NULL) {
1637         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1638         return JNI_FALSE;
1639     }
1640 
1641     jint* indices = NULL;
1642     int indicesIdx = 0;
1643     if (outIndices != NULL) {
1644         if (env->GetArrayLength(outIndices) > NI) {
1645             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1646         }
1647     }
1648 
1649     // Now lock down the resource object and start pulling stuff from it.
1650     res.lock();
1651 
1652     // Retrieve the XML attributes, if requested.
1653     const jsize NX = xmlParser->getAttributeCount();
1654     jsize ix=0;
1655     uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1656 
1657     static const ssize_t kXmlBlock = 0x10000000;
1658 
1659     // Now iterate through all of the attributes that the client has requested,
1660     // filling in each with whatever data we can find.
1661     ssize_t block = 0;
1662     uint32_t typeSetFlags;
1663     for (jsize ii=0; ii<NI; ii++) {
1664         const uint32_t curIdent = (uint32_t)src[ii];
1665 
1666         // Try to find a value for this attribute...
1667         value.dataType = Res_value::TYPE_NULL;
1668         value.data = Res_value::DATA_NULL_UNDEFINED;
1669         typeSetFlags = 0;
1670         config.density = 0;
1671 
1672         // Skip through XML attributes until the end or the next possible match.
1673         while (ix < NX && curIdent > curXmlAttr) {
1674             ix++;
1675             curXmlAttr = xmlParser->getAttributeNameResID(ix);
1676         }
1677         // Retrieve the current XML attribute if it matches, and step to next.
1678         if (ix < NX && curIdent == curXmlAttr) {
1679             block = kXmlBlock;
1680             xmlParser->getAttributeValue(ix, &value);
1681             ix++;
1682             curXmlAttr = xmlParser->getAttributeNameResID(ix);
1683         }
1684 
1685         //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1686         uint32_t resid = 0;
1687         if (value.dataType != Res_value::TYPE_NULL) {
1688             // Take care of resolving the found resource to its final value.
1689             //printf("Resolving attribute reference\n");
1690             ssize_t newBlock = res.resolveReference(&value, block, &resid,
1691                     &typeSetFlags, &config);
1692             if (kThrowOnBadId) {
1693                 if (newBlock == BAD_INDEX) {
1694                     jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1695                     return JNI_FALSE;
1696                 }
1697             }
1698             if (newBlock >= 0) block = newBlock;
1699         }
1700 
1701         // Deal with the special @null value -- it turns back to TYPE_NULL.
1702         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1703             value.dataType = Res_value::TYPE_NULL;
1704             value.data = Res_value::DATA_NULL_UNDEFINED;
1705         }
1706 
1707         //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1708 
1709         // Write the final value back to Java.
1710         dest[STYLE_TYPE] = value.dataType;
1711         dest[STYLE_DATA] = value.data;
1712         dest[STYLE_ASSET_COOKIE] =
1713             block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1714         dest[STYLE_RESOURCE_ID] = resid;
1715         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1716         dest[STYLE_DENSITY] = config.density;
1717 
1718         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1719             indicesIdx++;
1720             indices[indicesIdx] = ii;
1721         }
1722 
1723         dest += STYLE_NUM_ENTRIES;
1724     }
1725 
1726     res.unlock();
1727 
1728     if (indices != NULL) {
1729         indices[0] = indicesIdx;
1730         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1731     }
1732 
1733     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1734     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1735 
1736     return JNI_TRUE;
1737 }
1738 
android_content_AssetManager_getArraySize(JNIEnv * env,jobject clazz,jint id)1739 static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1740                                                        jint id)
1741 {
1742     AssetManager* am = assetManagerForJavaObject(env, clazz);
1743     if (am == NULL) {
1744         return 0;
1745     }
1746     const ResTable& res(am->getResources());
1747 
1748     res.lock();
1749     const ResTable::bag_entry* defStyleEnt = NULL;
1750     ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1751     res.unlock();
1752 
1753     return static_cast<jint>(bagOff);
1754 }
1755 
android_content_AssetManager_retrieveArray(JNIEnv * env,jobject clazz,jint id,jintArray outValues)1756 static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1757                                                         jint id,
1758                                                         jintArray outValues)
1759 {
1760     if (outValues == NULL) {
1761         jniThrowNullPointerException(env, "out values");
1762         return JNI_FALSE;
1763     }
1764 
1765     AssetManager* am = assetManagerForJavaObject(env, clazz);
1766     if (am == NULL) {
1767         return JNI_FALSE;
1768     }
1769     const ResTable& res(am->getResources());
1770     ResTable_config config;
1771     Res_value value;
1772     ssize_t block;
1773 
1774     const jsize NV = env->GetArrayLength(outValues);
1775 
1776     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1777     jint* dest = baseDest;
1778     if (dest == NULL) {
1779         jniThrowException(env, "java/lang/OutOfMemoryError", "");
1780         return JNI_FALSE;
1781     }
1782 
1783     // Now lock down the resource object and start pulling stuff from it.
1784     res.lock();
1785 
1786     const ResTable::bag_entry* arrayEnt = NULL;
1787     uint32_t arrayTypeSetFlags = 0;
1788     ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1789     const ResTable::bag_entry* endArrayEnt = arrayEnt +
1790         (bagOff >= 0 ? bagOff : 0);
1791 
1792     int i = 0;
1793     uint32_t typeSetFlags;
1794     while (i < NV && arrayEnt < endArrayEnt) {
1795         block = arrayEnt->stringBlock;
1796         typeSetFlags = arrayTypeSetFlags;
1797         config.density = 0;
1798         value = arrayEnt->map.value;
1799 
1800         uint32_t resid = 0;
1801         if (value.dataType != Res_value::TYPE_NULL) {
1802             // Take care of resolving the found resource to its final value.
1803             //printf("Resolving attribute reference\n");
1804             ssize_t newBlock = res.resolveReference(&value, block, &resid,
1805                     &typeSetFlags, &config);
1806             if (kThrowOnBadId) {
1807                 if (newBlock == BAD_INDEX) {
1808                     jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1809                     return JNI_FALSE;
1810                 }
1811             }
1812             if (newBlock >= 0) block = newBlock;
1813         }
1814 
1815         // Deal with the special @null value -- it turns back to TYPE_NULL.
1816         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1817             value.dataType = Res_value::TYPE_NULL;
1818             value.data = Res_value::DATA_NULL_UNDEFINED;
1819         }
1820 
1821         //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1822 
1823         // Write the final value back to Java.
1824         dest[STYLE_TYPE] = value.dataType;
1825         dest[STYLE_DATA] = value.data;
1826         dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
1827         dest[STYLE_RESOURCE_ID] = resid;
1828         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1829         dest[STYLE_DENSITY] = config.density;
1830         dest += STYLE_NUM_ENTRIES;
1831         i+= STYLE_NUM_ENTRIES;
1832         arrayEnt++;
1833     }
1834 
1835     i /= STYLE_NUM_ENTRIES;
1836 
1837     res.unlock();
1838 
1839     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1840 
1841     return i;
1842 }
1843 
android_content_AssetManager_openXmlAssetNative(JNIEnv * env,jobject clazz,jint cookie,jstring fileName)1844 static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1845                                                          jint cookie,
1846                                                          jstring fileName)
1847 {
1848     AssetManager* am = assetManagerForJavaObject(env, clazz);
1849     if (am == NULL) {
1850         return 0;
1851     }
1852 
1853     ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1854 
1855     ScopedUtfChars fileName8(env, fileName);
1856     if (fileName8.c_str() == NULL) {
1857         return 0;
1858     }
1859 
1860     int32_t assetCookie = static_cast<int32_t>(cookie);
1861     Asset* a = assetCookie
1862         ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1863         : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
1864 
1865     if (a == NULL) {
1866         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
1867         return 0;
1868     }
1869 
1870     const DynamicRefTable* dynamicRefTable =
1871             am->getResources().getDynamicRefTableForCookie(assetCookie);
1872     ResXMLTree* block = new ResXMLTree(dynamicRefTable);
1873     status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1874     a->close();
1875     delete a;
1876 
1877     if (err != NO_ERROR) {
1878         jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
1879         return 0;
1880     }
1881 
1882     return reinterpret_cast<jlong>(block);
1883 }
1884 
android_content_AssetManager_getArrayStringInfo(JNIEnv * env,jobject clazz,jint arrayResId)1885 static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1886                                                                  jint arrayResId)
1887 {
1888     AssetManager* am = assetManagerForJavaObject(env, clazz);
1889     if (am == NULL) {
1890         return NULL;
1891     }
1892     const ResTable& res(am->getResources());
1893 
1894     const ResTable::bag_entry* startOfBag;
1895     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1896     if (N < 0) {
1897         return NULL;
1898     }
1899 
1900     jintArray array = env->NewIntArray(N * 2);
1901     if (array == NULL) {
1902         res.unlockBag(startOfBag);
1903         return NULL;
1904     }
1905 
1906     Res_value value;
1907     const ResTable::bag_entry* bag = startOfBag;
1908     for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1909         jint stringIndex = -1;
1910         jint stringBlock = 0;
1911         value = bag->map.value;
1912 
1913         // Take care of resolving the found resource to its final value.
1914         stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1915         if (value.dataType == Res_value::TYPE_STRING) {
1916             stringIndex = value.data;
1917         }
1918 
1919         if (kThrowOnBadId) {
1920             if (stringBlock == BAD_INDEX) {
1921                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1922                 return array;
1923             }
1924         }
1925 
1926         //todo: It might be faster to allocate a C array to contain
1927         //      the blocknums and indices, put them in there and then
1928         //      do just one SetIntArrayRegion()
1929         env->SetIntArrayRegion(array, j, 1, &stringBlock);
1930         env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1931         j = j + 2;
1932     }
1933     res.unlockBag(startOfBag);
1934     return array;
1935 }
1936 
android_content_AssetManager_getArrayStringResource(JNIEnv * env,jobject clazz,jint arrayResId)1937 static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1938                                                                         jint arrayResId)
1939 {
1940     AssetManager* am = assetManagerForJavaObject(env, clazz);
1941     if (am == NULL) {
1942         return NULL;
1943     }
1944     const ResTable& res(am->getResources());
1945 
1946     const ResTable::bag_entry* startOfBag;
1947     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1948     if (N < 0) {
1949         return NULL;
1950     }
1951 
1952     jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
1953     if (env->ExceptionCheck()) {
1954         res.unlockBag(startOfBag);
1955         return NULL;
1956     }
1957 
1958     Res_value value;
1959     const ResTable::bag_entry* bag = startOfBag;
1960     size_t strLen = 0;
1961     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1962         value = bag->map.value;
1963         jstring str = NULL;
1964 
1965         // Take care of resolving the found resource to its final value.
1966         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1967         if (kThrowOnBadId) {
1968             if (block == BAD_INDEX) {
1969                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1970                 return array;
1971             }
1972         }
1973         if (value.dataType == Res_value::TYPE_STRING) {
1974             const ResStringPool* pool = res.getTableStringBlock(block);
1975             const char* str8 = pool->string8At(value.data, &strLen);
1976             if (str8 != NULL) {
1977                 str = env->NewStringUTF(str8);
1978             } else {
1979                 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1980                 str = env->NewString(reinterpret_cast<const jchar*>(str16),
1981                                      strLen);
1982             }
1983 
1984             // If one of our NewString{UTF} calls failed due to memory, an
1985             // exception will be pending.
1986             if (env->ExceptionCheck()) {
1987                 res.unlockBag(startOfBag);
1988                 return NULL;
1989             }
1990 
1991             env->SetObjectArrayElement(array, i, str);
1992 
1993             // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1994             // If we have a large amount of strings in our array, we might
1995             // overflow the local reference table of the VM.
1996             env->DeleteLocalRef(str);
1997         }
1998     }
1999     res.unlockBag(startOfBag);
2000     return array;
2001 }
2002 
android_content_AssetManager_getArrayIntResource(JNIEnv * env,jobject clazz,jint arrayResId)2003 static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
2004                                                                         jint arrayResId)
2005 {
2006     AssetManager* am = assetManagerForJavaObject(env, clazz);
2007     if (am == NULL) {
2008         return NULL;
2009     }
2010     const ResTable& res(am->getResources());
2011 
2012     const ResTable::bag_entry* startOfBag;
2013     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
2014     if (N < 0) {
2015         return NULL;
2016     }
2017 
2018     jintArray array = env->NewIntArray(N);
2019     if (array == NULL) {
2020         res.unlockBag(startOfBag);
2021         return NULL;
2022     }
2023 
2024     Res_value value;
2025     const ResTable::bag_entry* bag = startOfBag;
2026     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
2027         value = bag->map.value;
2028 
2029         // Take care of resolving the found resource to its final value.
2030         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
2031         if (kThrowOnBadId) {
2032             if (block == BAD_INDEX) {
2033                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
2034                 return array;
2035             }
2036         }
2037         if (value.dataType >= Res_value::TYPE_FIRST_INT
2038                 && value.dataType <= Res_value::TYPE_LAST_INT) {
2039             int intVal = value.data;
2040             env->SetIntArrayRegion(array, i, 1, &intVal);
2041         }
2042     }
2043     res.unlockBag(startOfBag);
2044     return array;
2045 }
2046 
android_content_AssetManager_getStyleAttributes(JNIEnv * env,jobject clazz,jint styleId)2047 static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
2048                                                                  jint styleId)
2049 {
2050     AssetManager* am = assetManagerForJavaObject(env, clazz);
2051     if (am == NULL) {
2052         return NULL;
2053     }
2054     const ResTable& res(am->getResources());
2055 
2056     const ResTable::bag_entry* startOfBag;
2057     const ssize_t N = res.lockBag(styleId, &startOfBag);
2058     if (N < 0) {
2059         return NULL;
2060     }
2061 
2062     jintArray array = env->NewIntArray(N);
2063     if (array == NULL) {
2064         res.unlockBag(startOfBag);
2065         return NULL;
2066     }
2067 
2068     const ResTable::bag_entry* bag = startOfBag;
2069     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
2070         int resourceId = bag->map.name.ident;
2071         env->SetIntArrayRegion(array, i, 1, &resourceId);
2072     }
2073     res.unlockBag(startOfBag);
2074     return array;
2075 }
2076 
android_content_AssetManager_init(JNIEnv * env,jobject clazz,jboolean isSystem)2077 static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
2078 {
2079     if (isSystem) {
2080         verifySystemIdmaps();
2081     }
2082     AssetManager* am = new AssetManager();
2083     if (am == NULL) {
2084         jniThrowException(env, "java/lang/OutOfMemoryError", "");
2085         return;
2086     }
2087 
2088     am->addDefaultAssets();
2089 
2090     ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
2091     env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
2092 }
2093 
android_content_AssetManager_destroy(JNIEnv * env,jobject clazz)2094 static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
2095 {
2096     AssetManager* am = (AssetManager*)
2097         (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
2098     ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
2099     if (am != NULL) {
2100         delete am;
2101         env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
2102     }
2103 }
2104 
android_content_AssetManager_getGlobalAssetCount(JNIEnv * env,jobject clazz)2105 static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
2106 {
2107     return Asset::getGlobalCount();
2108 }
2109 
android_content_AssetManager_getAssetAllocations(JNIEnv * env,jobject clazz)2110 static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
2111 {
2112     String8 alloc = Asset::getAssetAllocations();
2113     if (alloc.length() <= 0) {
2114         return NULL;
2115     }
2116 
2117     jstring str = env->NewStringUTF(alloc.string());
2118     return str;
2119 }
2120 
android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv * env,jobject clazz)2121 static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
2122 {
2123     return AssetManager::getGlobalCount();
2124 }
2125 
2126 // ----------------------------------------------------------------------------
2127 
2128 /*
2129  * JNI registration.
2130  */
2131 static const JNINativeMethod gAssetManagerMethods[] = {
2132     /* name, signature, funcPtr */
2133 
2134     // Basic asset stuff.
2135     { "openAsset",      "(Ljava/lang/String;I)J",
2136         (void*) android_content_AssetManager_openAsset },
2137     { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2138         (void*) android_content_AssetManager_openAssetFd },
2139     { "openNonAssetNative", "(ILjava/lang/String;I)J",
2140         (void*) android_content_AssetManager_openNonAssetNative },
2141     { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2142         (void*) android_content_AssetManager_openNonAssetFdNative },
2143     { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
2144         (void*) android_content_AssetManager_list },
2145     { "destroyAsset",   "(J)V",
2146         (void*) android_content_AssetManager_destroyAsset },
2147     { "readAssetChar",  "(J)I",
2148         (void*) android_content_AssetManager_readAssetChar },
2149     { "readAsset",      "(J[BII)I",
2150         (void*) android_content_AssetManager_readAsset },
2151     { "seekAsset",      "(JJI)J",
2152         (void*) android_content_AssetManager_seekAsset },
2153     { "getAssetLength", "!(J)J",
2154         (void*) android_content_AssetManager_getAssetLength },
2155     { "getAssetRemainingLength", "!(J)J",
2156         (void*) android_content_AssetManager_getAssetRemainingLength },
2157     { "addAssetPathNative", "(Ljava/lang/String;Z)I",
2158         (void*) android_content_AssetManager_addAssetPath },
2159     { "addOverlayPathNative",   "(Ljava/lang/String;)I",
2160         (void*) android_content_AssetManager_addOverlayPath },
2161     { "isUpToDate",     "()Z",
2162         (void*) android_content_AssetManager_isUpToDate },
2163 
2164     // Resources.
2165     { "getLocales",      "()[Ljava/lang/String;",
2166         (void*) android_content_AssetManager_getLocales },
2167     { "getNonSystemLocales", "()[Ljava/lang/String;",
2168         (void*) android_content_AssetManager_getNonSystemLocales },
2169     { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
2170         (void*) android_content_AssetManager_getSizeConfigurations },
2171     { "setConfiguration", "!(IILjava/lang/String;IIIIIIIIIIIIII)V",
2172         (void*) android_content_AssetManager_setConfiguration },
2173     { "getResourceIdentifier","!(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
2174         (void*) android_content_AssetManager_getResourceIdentifier },
2175     { "getResourceName","!(I)Ljava/lang/String;",
2176         (void*) android_content_AssetManager_getResourceName },
2177     { "getResourcePackageName","!(I)Ljava/lang/String;",
2178         (void*) android_content_AssetManager_getResourcePackageName },
2179     { "getResourceTypeName","!(I)Ljava/lang/String;",
2180         (void*) android_content_AssetManager_getResourceTypeName },
2181     { "getResourceEntryName","!(I)Ljava/lang/String;",
2182         (void*) android_content_AssetManager_getResourceEntryName },
2183     { "loadResourceValue","!(ISLandroid/util/TypedValue;Z)I",
2184         (void*) android_content_AssetManager_loadResourceValue },
2185     { "loadResourceBagValue","!(IILandroid/util/TypedValue;Z)I",
2186         (void*) android_content_AssetManager_loadResourceBagValue },
2187     { "getStringBlockCount","!()I",
2188         (void*) android_content_AssetManager_getStringBlockCount },
2189     { "getNativeStringBlock","!(I)J",
2190         (void*) android_content_AssetManager_getNativeStringBlock },
2191     { "getCookieName","(I)Ljava/lang/String;",
2192         (void*) android_content_AssetManager_getCookieName },
2193     { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
2194         (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
2195 
2196     // Themes.
2197     { "newTheme", "()J",
2198         (void*) android_content_AssetManager_newTheme },
2199     { "deleteTheme", "(J)V",
2200         (void*) android_content_AssetManager_deleteTheme },
2201     { "applyThemeStyle", "(JIZ)V",
2202         (void*) android_content_AssetManager_applyThemeStyle },
2203     { "copyTheme", "(JJ)V",
2204         (void*) android_content_AssetManager_copyTheme },
2205     { "clearTheme", "(J)V",
2206         (void*) android_content_AssetManager_clearTheme },
2207     { "loadThemeAttributeValue", "!(JILandroid/util/TypedValue;Z)I",
2208         (void*) android_content_AssetManager_loadThemeAttributeValue },
2209     { "getThemeChangingConfigurations", "!(J)I",
2210         (void*) android_content_AssetManager_getThemeChangingConfigurations },
2211     { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
2212         (void*) android_content_AssetManager_dumpTheme },
2213     { "applyStyle","!(JIIJ[I[I[I)Z",
2214         (void*) android_content_AssetManager_applyStyle },
2215     { "resolveAttrs","!(JII[I[I[I[I)Z",
2216         (void*) android_content_AssetManager_resolveAttrs },
2217     { "retrieveAttributes","!(J[I[I[I)Z",
2218         (void*) android_content_AssetManager_retrieveAttributes },
2219     { "getArraySize","!(I)I",
2220         (void*) android_content_AssetManager_getArraySize },
2221     { "retrieveArray","!(I[I)I",
2222         (void*) android_content_AssetManager_retrieveArray },
2223 
2224     // XML files.
2225     { "openXmlAssetNative", "(ILjava/lang/String;)J",
2226         (void*) android_content_AssetManager_openXmlAssetNative },
2227 
2228     // Arrays.
2229     { "getArrayStringResource","(I)[Ljava/lang/String;",
2230         (void*) android_content_AssetManager_getArrayStringResource },
2231     { "getArrayStringInfo","!(I)[I",
2232         (void*) android_content_AssetManager_getArrayStringInfo },
2233     { "getArrayIntResource","!(I)[I",
2234         (void*) android_content_AssetManager_getArrayIntResource },
2235     { "getStyleAttributes","!(I)[I",
2236         (void*) android_content_AssetManager_getStyleAttributes },
2237 
2238     // Bookkeeping.
2239     { "init",           "(Z)V",
2240         (void*) android_content_AssetManager_init },
2241     { "destroy",        "()V",
2242         (void*) android_content_AssetManager_destroy },
2243     { "getGlobalAssetCount", "()I",
2244         (void*) android_content_AssetManager_getGlobalAssetCount },
2245     { "getAssetAllocations", "()Ljava/lang/String;",
2246         (void*) android_content_AssetManager_getAssetAllocations },
2247     { "getGlobalAssetManagerCount", "()I",
2248         (void*) android_content_AssetManager_getGlobalAssetManagerCount },
2249 };
2250 
register_android_content_AssetManager(JNIEnv * env)2251 int register_android_content_AssetManager(JNIEnv* env)
2252 {
2253     jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
2254     gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
2255     gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
2256     gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
2257                                                  "Ljava/lang/CharSequence;");
2258     gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
2259     gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
2260     gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
2261                                                                  "changingConfigurations", "I");
2262     gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
2263 
2264     jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
2265     gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
2266                                                       "Landroid/os/ParcelFileDescriptor;");
2267     gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
2268     gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
2269 
2270     jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
2271     gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
2272 
2273     jclass stringClass = FindClassOrDie(env, "java/lang/String");
2274     g_stringClass = MakeGlobalRefOrDie(env, stringClass);
2275 
2276     jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
2277     gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
2278     gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
2279                                                        "<init>", "()V");
2280     gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
2281                                                "(ILjava/lang/Object;)V");
2282 
2283     jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
2284     gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
2285     gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass,
2286             "<init>", "()V");
2287     gConfigurationOffsets.mSmallestScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
2288             "smallestScreenWidthDp", "I");
2289     gConfigurationOffsets.mScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
2290             "screenWidthDp", "I");
2291     gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass,
2292             "screenHeightDp", "I");
2293 
2294     return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
2295                                 NELEM(gAssetManagerMethods));
2296 }
2297 
2298 }; // namespace android
2299