• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "ResourceType"
18 //#define LOG_NDEBUG 0
19 
20 #include <ctype.h>
21 #include <memory.h>
22 #include <stddef.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <algorithm>
28 #include <fstream>
29 #include <limits>
30 #include <map>
31 #include <memory>
32 #include <set>
33 #include <type_traits>
34 #include <vector>
35 
36 #include <android-base/file.h>
37 #include <android-base/macros.h>
38 #include <android-base/utf8.h>
39 #include <androidfw/ByteBucketArray.h>
40 #include <androidfw/ResourceTypes.h>
41 #include <androidfw/TypeWrappers.h>
42 #include <cutils/atomic.h>
43 #include <utils/ByteOrder.h>
44 #include <utils/Log.h>
45 #include <utils/String16.h>
46 #include <utils/String8.h>
47 
48 #ifdef __ANDROID__
49 #include <binder/TextOutput.h>
50 
51 #endif
52 
53 #ifndef INT32_MAX
54 #define INT32_MAX ((int32_t)(2147483647))
55 #endif
56 
57 using namespace std::literals;
58 
59 namespace android {
60 
61 #if defined(_WIN32)
62 #undef  nhtol
63 #undef  htonl
64 #define ntohl(x)    ( ((x) << 24) | (((x) >> 24) & 255) | (((x) << 8) & 0xff0000) | (((x) >> 8) & 0xff00) )
65 #define htonl(x)    ntohl(x)
66 #define ntohs(x)    ( (((x) << 8) & 0xff00) | (((x) >> 8) & 255) )
67 #define htons(x)    ntohs(x)
68 #endif
69 
70 #define IDMAP_MAGIC             0x504D4449
71 
72 #define APP_PACKAGE_ID      0x7f
73 #define SYS_PACKAGE_ID      0x01
74 
75 static const bool kDebugStringPoolNoisy = false;
76 static const bool kDebugXMLNoisy = false;
77 static const bool kDebugTableNoisy = false;
78 static const bool kDebugTableGetEntry = false;
79 static const bool kDebugTableSuperNoisy = false;
80 static const bool kDebugLoadTableNoisy = false;
81 static const bool kDebugLoadTableSuperNoisy = false;
82 static const bool kDebugTableTheme = false;
83 static const bool kDebugResXMLTree = false;
84 static const bool kDebugLibNoisy = false;
85 
86 // TODO: This code uses 0xFFFFFFFF converted to bag_set* as a sentinel value. This is bad practice.
87 
88 // Standard C isspace() is only required to look at the low byte of its input, so
89 // produces incorrect results for UTF-16 characters.  For safety's sake, assume that
90 // any high-byte UTF-16 code point is not whitespace.
isspace16(char16_t c)91 inline int isspace16(char16_t c) {
92     return (c < 0x0080 && isspace(c));
93 }
94 
95 template<typename T>
max(T a,T b)96 inline static T max(T a, T b) {
97     return a > b ? a : b;
98 }
99 
100 // range checked; guaranteed to NUL-terminate within the stated number of available slots
101 // NOTE: if this truncates the dst string due to running out of space, no attempt is
102 // made to avoid splitting surrogate pairs.
strcpy16_dtoh(char16_t * dst,const uint16_t * src,size_t avail)103 static void strcpy16_dtoh(char16_t* dst, const uint16_t* src, size_t avail)
104 {
105     char16_t* last = dst + avail - 1;
106     while (*src && (dst < last)) {
107         char16_t s = dtohs(static_cast<char16_t>(*src));
108         *dst++ = s;
109         src++;
110     }
111     *dst = 0;
112 }
113 
validate_chunk(const incfs::map_ptr<ResChunk_header> & chunk,size_t minSize,const incfs::map_ptr<uint8_t> dataEnd,const char * name)114 static status_t validate_chunk(const incfs::map_ptr<ResChunk_header>& chunk,
115                                size_t minSize,
116                                const incfs::map_ptr<uint8_t> dataEnd,
117                                const char* name)
118 {
119     if (!chunk) {
120       return BAD_TYPE;
121     }
122 
123     const uint16_t headerSize = dtohs(chunk->headerSize);
124     const uint32_t size = dtohl(chunk->size);
125 
126     if (headerSize >= minSize) {
127         if (headerSize <= size) {
128             if (((headerSize|size)&0x3) == 0) {
129                 if ((size_t)size <= (size_t)(dataEnd-chunk.convert<uint8_t>())) {
130                     return NO_ERROR;
131                 }
132                 ALOGW("%s data size 0x%x extends beyond resource end %p.",
133                      name, size, (void*)(dataEnd-chunk.convert<uint8_t>()));
134                 return BAD_TYPE;
135             }
136             ALOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.",
137                  name, (int)size, (int)headerSize);
138             return BAD_TYPE;
139         }
140         ALOGW("%s size 0x%x is smaller than header size 0x%x.",
141              name, size, headerSize);
142         return BAD_TYPE;
143     }
144     ALOGW("%s header size 0x%04x is too small.",
145          name, headerSize);
146     return BAD_TYPE;
147 }
148 
fill9patchOffsets(Res_png_9patch * patch)149 static void fill9patchOffsets(Res_png_9patch* patch) {
150     patch->xDivsOffset = sizeof(Res_png_9patch);
151     patch->yDivsOffset = patch->xDivsOffset + (patch->numXDivs * sizeof(int32_t));
152     patch->colorsOffset = patch->yDivsOffset + (patch->numYDivs * sizeof(int32_t));
153 }
154 
copyFrom_dtoh(const Res_value & src)155 void Res_value::copyFrom_dtoh(const Res_value& src)
156 {
157     size = dtohs(src.size);
158     res0 = src.res0;
159     dataType = src.dataType;
160     data = dtohl(src.data);
161 }
162 
deviceToFile()163 void Res_png_9patch::deviceToFile()
164 {
165     int32_t* xDivs = getXDivs();
166     for (int i = 0; i < numXDivs; i++) {
167         xDivs[i] = htonl(xDivs[i]);
168     }
169     int32_t* yDivs = getYDivs();
170     for (int i = 0; i < numYDivs; i++) {
171         yDivs[i] = htonl(yDivs[i]);
172     }
173     paddingLeft = htonl(paddingLeft);
174     paddingRight = htonl(paddingRight);
175     paddingTop = htonl(paddingTop);
176     paddingBottom = htonl(paddingBottom);
177     uint32_t* colors = getColors();
178     for (int i=0; i<numColors; i++) {
179         colors[i] = htonl(colors[i]);
180     }
181 }
182 
fileToDevice()183 void Res_png_9patch::fileToDevice()
184 {
185     int32_t* xDivs = getXDivs();
186     for (int i = 0; i < numXDivs; i++) {
187         xDivs[i] = ntohl(xDivs[i]);
188     }
189     int32_t* yDivs = getYDivs();
190     for (int i = 0; i < numYDivs; i++) {
191         yDivs[i] = ntohl(yDivs[i]);
192     }
193     paddingLeft = ntohl(paddingLeft);
194     paddingRight = ntohl(paddingRight);
195     paddingTop = ntohl(paddingTop);
196     paddingBottom = ntohl(paddingBottom);
197     uint32_t* colors = getColors();
198     for (int i=0; i<numColors; i++) {
199         colors[i] = ntohl(colors[i]);
200     }
201 }
202 
serializedSize() const203 size_t Res_png_9patch::serializedSize() const
204 {
205     // The size of this struct is 32 bytes on the 32-bit target system
206     // 4 * int8_t
207     // 4 * int32_t
208     // 3 * uint32_t
209     return 32
210             + numXDivs * sizeof(int32_t)
211             + numYDivs * sizeof(int32_t)
212             + numColors * sizeof(uint32_t);
213 }
214 
serialize(const Res_png_9patch & patch,const int32_t * xDivs,const int32_t * yDivs,const uint32_t * colors)215 void* Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs,
216                                 const int32_t* yDivs, const uint32_t* colors)
217 {
218     // Use calloc since we're going to leave a few holes in the data
219     // and want this to run cleanly under valgrind
220     void* newData = calloc(1, patch.serializedSize());
221     serialize(patch, xDivs, yDivs, colors, newData);
222     return newData;
223 }
224 
serialize(const Res_png_9patch & patch,const int32_t * xDivs,const int32_t * yDivs,const uint32_t * colors,void * outData)225 void Res_png_9patch::serialize(const Res_png_9patch& patch, const int32_t* xDivs,
226                                const int32_t* yDivs, const uint32_t* colors, void* outData)
227 {
228     uint8_t* data = (uint8_t*) outData;
229     memcpy(data, &patch.wasDeserialized, 4);     // copy  wasDeserialized, numXDivs, numYDivs, numColors
230     memcpy(data + 12, &patch.paddingLeft, 16);   // copy paddingXXXX
231     data += 32;
232 
233     memcpy(data, xDivs, patch.numXDivs * sizeof(int32_t));
234     data +=  patch.numXDivs * sizeof(int32_t);
235     memcpy(data, yDivs, patch.numYDivs * sizeof(int32_t));
236     data +=  patch.numYDivs * sizeof(int32_t);
237     memcpy(data, colors, patch.numColors * sizeof(uint32_t));
238 
239     fill9patchOffsets(reinterpret_cast<Res_png_9patch*>(outData));
240 }
241 
IsFabricatedOverlayName(std::string_view path)242 bool IsFabricatedOverlayName(std::string_view path) {
243   static constexpr auto suffixFrro = ".frro"sv;
244   static constexpr auto suffixIdmap = ".frro@idmap"sv;
245 
246   return (path.size() > suffixFrro.size() && path.ends_with(suffixFrro))
247         || (path.size() > suffixIdmap.size() && path.ends_with(suffixIdmap));
248 }
249 
IsFabricatedOverlay(std::string_view path)250 bool IsFabricatedOverlay(std::string_view path) {
251   if (!IsFabricatedOverlayName(path)) {
252     return false;
253   }
254   std::string path_copy;
255   if (path[path.size()] != '\0') {
256     path_copy.assign(path);
257     path = path_copy;
258   }
259   auto fd = base::unique_fd(base::utf8::open(path.data(), O_RDONLY|O_CLOEXEC|O_BINARY));
260   if (fd < 0) {
261     return false;
262   }
263   return IsFabricatedOverlay(fd);
264 }
265 
IsFabricatedOverlay(base::borrowed_fd fd)266 bool IsFabricatedOverlay(base::borrowed_fd fd) {
267   uint32_t magic;
268   if (!base::ReadFullyAtOffset(fd, &magic, sizeof(magic), 0)) {
269     return false;
270   }
271   return magic == kFabricatedOverlayMagic;
272 }
273 
assertIdmapHeader(const void * idmap,size_t size)274 static bool assertIdmapHeader(const void* idmap, size_t size) {
275     if (reinterpret_cast<uintptr_t>(idmap) & 0x03) {
276         ALOGE("idmap: header is not word aligned");
277         return false;
278     }
279 
280     if (size < ResTable::IDMAP_HEADER_SIZE_BYTES) {
281         ALOGW("idmap: header too small (%d bytes)", (uint32_t) size);
282         return false;
283     }
284 
285     const uint32_t magic = htodl(*reinterpret_cast<const uint32_t*>(idmap));
286     if (magic != IDMAP_MAGIC) {
287         ALOGW("idmap: no magic found in header (is 0x%08x, expected 0x%08x)",
288              magic, IDMAP_MAGIC);
289         return false;
290     }
291 
292     const uint32_t version = htodl(*(reinterpret_cast<const uint32_t*>(idmap) + 1));
293     if (version != ResTable::IDMAP_CURRENT_VERSION) {
294         // We are strict about versions because files with this format are
295         // auto-generated and don't need backwards compatibility.
296         ALOGW("idmap: version mismatch in header (is 0x%08x, expected 0x%08x)",
297                 version, ResTable::IDMAP_CURRENT_VERSION);
298         return false;
299     }
300     return true;
301 }
302 
303 class IdmapEntries {
304 public:
IdmapEntries()305     IdmapEntries() : mData(NULL) {}
306 
hasEntries() const307     bool hasEntries() const {
308         if (mData == NULL) {
309             return false;
310         }
311 
312         return (dtohs(*mData) > 0);
313     }
314 
byteSize() const315     size_t byteSize() const {
316         if (mData == NULL) {
317             return 0;
318         }
319         uint16_t entryCount = dtohs(mData[2]);
320         return (sizeof(uint16_t) * 4) + (sizeof(uint32_t) * static_cast<size_t>(entryCount));
321     }
322 
targetTypeId() const323     uint8_t targetTypeId() const {
324         if (mData == NULL) {
325             return 0;
326         }
327         return dtohs(mData[0]);
328     }
329 
overlayTypeId() const330     uint8_t overlayTypeId() const {
331         if (mData == NULL) {
332             return 0;
333         }
334         return dtohs(mData[1]);
335     }
336 
setTo(const void * entryHeader,size_t size)337     status_t setTo(const void* entryHeader, size_t size) {
338         if (reinterpret_cast<uintptr_t>(entryHeader) & 0x03) {
339             ALOGE("idmap: entry header is not word aligned");
340             return UNKNOWN_ERROR;
341         }
342 
343         if (size < sizeof(uint16_t) * 4) {
344             ALOGE("idmap: entry header is too small (%u bytes)", (uint32_t) size);
345             return UNKNOWN_ERROR;
346         }
347 
348         const uint16_t* header = reinterpret_cast<const uint16_t*>(entryHeader);
349         const uint16_t targetTypeId = dtohs(header[0]);
350         const uint16_t overlayTypeId = dtohs(header[1]);
351         if (targetTypeId == 0 || overlayTypeId == 0 || targetTypeId > 255 || overlayTypeId > 255) {
352             ALOGE("idmap: invalid type map (%u -> %u)", targetTypeId, overlayTypeId);
353             return UNKNOWN_ERROR;
354         }
355 
356         uint16_t entryCount = dtohs(header[2]);
357         if (size < sizeof(uint32_t) * (entryCount + 2)) {
358             ALOGE("idmap: too small (%u bytes) for the number of entries (%u)",
359                     (uint32_t) size, (uint32_t) entryCount);
360             return UNKNOWN_ERROR;
361         }
362         mData = header;
363         return NO_ERROR;
364     }
365 
lookup(uint16_t entryId,uint16_t * outEntryId) const366     status_t lookup(uint16_t entryId, uint16_t* outEntryId) const {
367         uint16_t entryCount = dtohs(mData[2]);
368         uint16_t offset = dtohs(mData[3]);
369 
370         if (entryId < offset) {
371             // The entry is not present in this idmap
372             return BAD_INDEX;
373         }
374 
375         entryId -= offset;
376 
377         if (entryId >= entryCount) {
378             // The entry is not present in this idmap
379             return BAD_INDEX;
380         }
381 
382         // It is safe to access the type here without checking the size because
383         // we have checked this when it was first loaded.
384         const uint32_t* entries = reinterpret_cast<const uint32_t*>(mData) + 2;
385         uint32_t mappedEntry = dtohl(entries[entryId]);
386         if (mappedEntry == 0xffffffff) {
387             // This entry is not present in this idmap
388             return BAD_INDEX;
389         }
390         *outEntryId = static_cast<uint16_t>(mappedEntry);
391         return NO_ERROR;
392     }
393 
394 private:
395     const uint16_t* mData;
396 };
397 
parseIdmap(const void * idmap,size_t size,uint8_t * outPackageId,KeyedVector<uint8_t,IdmapEntries> * outMap)398 status_t parseIdmap(const void* idmap, size_t size, uint8_t* outPackageId, KeyedVector<uint8_t, IdmapEntries>* outMap) {
399     if (!assertIdmapHeader(idmap, size)) {
400         return UNKNOWN_ERROR;
401     }
402 
403     size -= ResTable::IDMAP_HEADER_SIZE_BYTES;
404     if (size < sizeof(uint16_t) * 2) {
405         ALOGE("idmap: too small to contain any mapping");
406         return UNKNOWN_ERROR;
407     }
408 
409     const uint16_t* data = reinterpret_cast<const uint16_t*>(
410             reinterpret_cast<const uint8_t*>(idmap) + ResTable::IDMAP_HEADER_SIZE_BYTES);
411 
412     uint16_t targetPackageId = dtohs(*(data++));
413     if (targetPackageId == 0 || targetPackageId > 255) {
414         ALOGE("idmap: target package ID is invalid (%02x)", targetPackageId);
415         return UNKNOWN_ERROR;
416     }
417 
418     uint16_t mapCount = dtohs(*(data++));
419     if (mapCount == 0) {
420         ALOGE("idmap: no mappings");
421         return UNKNOWN_ERROR;
422     }
423 
424     if (mapCount > 255) {
425         ALOGW("idmap: too many mappings. Only 255 are possible but %u are present", (uint32_t) mapCount);
426     }
427 
428     while (size > sizeof(uint16_t) * 4) {
429         IdmapEntries entries;
430         status_t err = entries.setTo(data, size);
431         if (err != NO_ERROR) {
432             return err;
433         }
434 
435         ssize_t index = outMap->add(entries.overlayTypeId(), entries);
436         if (index < 0) {
437             return NO_MEMORY;
438         }
439 
440         data += entries.byteSize() / sizeof(uint16_t);
441         size -= entries.byteSize();
442     }
443 
444     if (outPackageId != NULL) {
445         *outPackageId = static_cast<uint8_t>(targetPackageId);
446     }
447     return NO_ERROR;
448 }
449 
deserialize(void * inData)450 Res_png_9patch* Res_png_9patch::deserialize(void* inData)
451 {
452 
453     Res_png_9patch* patch = reinterpret_cast<Res_png_9patch*>(inData);
454     patch->wasDeserialized = true;
455     fill9patchOffsets(patch);
456 
457     return patch;
458 }
459 
460 // --------------------------------------------------------------------
461 // --------------------------------------------------------------------
462 // --------------------------------------------------------------------
463 
ResStringPool()464 ResStringPool::ResStringPool() : mError(NO_INIT), mOwnedData(NULL), mHeader(NULL), mCache(NULL) {
465 }
466 
ResStringPool(bool optimize_name_lookups)467 ResStringPool::ResStringPool(bool optimize_name_lookups) : ResStringPool() {
468   if (optimize_name_lookups) {
469     mIndexLookupCache.emplace();
470   }
471 }
472 
ResStringPool(const void * data,size_t size,bool copyData,bool optimize_name_lookups)473 ResStringPool::ResStringPool(const void* data, size_t size, bool copyData,
474                              bool optimize_name_lookups)
475     : ResStringPool(optimize_name_lookups) {
476   setTo(data, size, copyData);
477 }
478 
~ResStringPool()479 ResStringPool::~ResStringPool()
480 {
481     uninit();
482 }
483 
setToEmpty()484 void ResStringPool::setToEmpty()
485 {
486     uninit();
487 
488     mOwnedData = calloc(1, sizeof(ResStringPool_header));
489     ResStringPool_header* header = (ResStringPool_header*) mOwnedData;
490     mSize = 0;
491     mEntries = NULL;
492     mStrings = NULL;
493     mStringPoolSize = 0;
494     mEntryStyles = NULL;
495     mStyles = NULL;
496     mStylePoolSize = 0;
497     mHeader = (const ResStringPool_header*) header;
498 }
499 
setTo(incfs::map_ptr<void> data,size_t size,bool copyData)500 status_t ResStringPool::setTo(incfs::map_ptr<void> data, size_t size, bool copyData)
501 {
502     if (!data || !size) {
503         return (mError=BAD_TYPE);
504     }
505 
506     uninit();
507 
508     // The chunk must be at least the size of the string pool header.
509     if (size < sizeof(ResStringPool_header)) {
510         ALOGW("Bad string block: data size %zu is too small to be a string block", size);
511         return (mError=BAD_TYPE);
512     }
513 
514     // The data is at least as big as a ResChunk_header, so we can safely validate the other
515     // header fields.
516     // `data + size` is safe because the source of `size` comes from the kernel/filesystem.
517     const auto chunk_header = data.convert<ResChunk_header>();
518     if (validate_chunk(chunk_header, sizeof(ResStringPool_header), data.convert<uint8_t>() + size,
519                        "ResStringPool_header") != NO_ERROR) {
520         ALOGW("Bad string block: malformed block dimensions");
521         return (mError=BAD_TYPE);
522     }
523 
524     const bool notDeviceEndian = htods(0xf0) != 0xf0;
525 
526     if (copyData || notDeviceEndian) {
527         mOwnedData = malloc(size);
528         if (mOwnedData == NULL) {
529             return (mError=NO_MEMORY);
530         }
531 
532         if (!data.convert<uint8_t>().verify(size)) {
533             return (mError=NO_MEMORY);
534         }
535 
536         memcpy(mOwnedData, data.unsafe_ptr(), size);
537         data = mOwnedData;
538     }
539 
540     // The size has been checked, so it is safe to read the data in the ResStringPool_header
541     // data structure.
542     const auto header = data.convert<ResStringPool_header>();
543     if (!header) {
544       return (mError=BAD_TYPE);
545     }
546 
547     mHeader = header.verified();
548     if (notDeviceEndian) {
549         ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader.unsafe_ptr());
550         h->header.headerSize = dtohs(mHeader->header.headerSize);
551         h->header.type = dtohs(mHeader->header.type);
552         h->header.size = dtohl(mHeader->header.size);
553         h->stringCount = dtohl(mHeader->stringCount);
554         h->styleCount = dtohl(mHeader->styleCount);
555         h->flags = dtohl(mHeader->flags);
556         h->stringsStart = dtohl(mHeader->stringsStart);
557         h->stylesStart = dtohl(mHeader->stylesStart);
558     }
559 
560     if (mHeader->header.headerSize > mHeader->header.size
561             || mHeader->header.size > size) {
562         ALOGW("Bad string block: header size %d or total size %d is larger than data size %d\n",
563                 (int)mHeader->header.headerSize, (int)mHeader->header.size, (int)size);
564         return (mError=BAD_TYPE);
565     }
566     mSize = mHeader->header.size;
567     mEntries = data.offset(mHeader->header.headerSize).convert<uint32_t>();
568 
569     if (mHeader->stringCount > 0) {
570         if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount)  // uint32 overflow?
571             || (mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t)))
572                 > size) {
573             ALOGW("Bad string block: entry of %d items extends past data size %d\n",
574                     (int)(mHeader->header.headerSize+(mHeader->stringCount*sizeof(uint32_t))),
575                     (int)size);
576             return (mError=BAD_TYPE);
577         }
578 
579         size_t charSize;
580         if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
581             charSize = sizeof(uint8_t);
582         } else {
583             charSize = sizeof(uint16_t);
584         }
585 
586         // There should be at least space for the smallest string
587         // (2 bytes length, null terminator).
588         if (mHeader->stringsStart >= (mSize - sizeof(uint16_t))) {
589             ALOGW("Bad string block: string pool starts at %d, after total size %d\n",
590                     (int)mHeader->stringsStart, (int)mHeader->header.size);
591             return (mError=BAD_TYPE);
592         }
593 
594         mStrings = data.offset(mHeader->stringsStart).convert<void>();
595         if (mHeader->styleCount == 0) {
596             mStringPoolSize = (mSize - mHeader->stringsStart) / charSize;
597         } else {
598             // check invariant: styles starts before end of data
599             if (mHeader->stylesStart >= (mSize - sizeof(uint16_t))) {
600                 ALOGW("Bad style block: style block starts at %d past data size of %d\n",
601                     (int)mHeader->stylesStart, (int)mHeader->header.size);
602                 return (mError=BAD_TYPE);
603             }
604             // check invariant: styles follow the strings
605             if (mHeader->stylesStart <= mHeader->stringsStart) {
606                 ALOGW("Bad style block: style block starts at %d, before strings at %d\n",
607                     (int)mHeader->stylesStart, (int)mHeader->stringsStart);
608                 return (mError=BAD_TYPE);
609             }
610             mStringPoolSize =
611                 (mHeader->stylesStart-mHeader->stringsStart)/charSize;
612         }
613 
614         // check invariant: stringCount > 0 requires a string pool to exist
615         if (mStringPoolSize == 0) {
616             ALOGW("Bad string block: stringCount is %d but pool size is 0\n",
617                   (int)mHeader->stringCount);
618             return (mError=BAD_TYPE);
619         }
620 
621         if (notDeviceEndian) {
622             size_t i;
623             auto e = const_cast<uint32_t*>(mEntries.unsafe_ptr());
624             for (i=0; i<mHeader->stringCount; i++) {
625                 e[i] = dtohl(e[i]);
626             }
627             if (!(mHeader->flags&ResStringPool_header::UTF8_FLAG)) {
628                 uint16_t* s = const_cast<uint16_t*>(mStrings.convert<uint16_t>().unsafe_ptr());
629                 for (i=0; i<mStringPoolSize; i++) {
630                     s[i] = dtohs(s[i]);
631                 }
632             }
633         }
634 
635         if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
636             auto end = mStrings.convert<uint8_t>() + (mStringPoolSize-1);
637             if (!end || end.value() != 0) {
638                 ALOGW("Bad string block: last string is not 0-terminated\n");
639                 return (mError=BAD_TYPE);
640             }
641         } else {
642             auto end = mStrings.convert<uint16_t>() + (mStringPoolSize-1);
643             if (!end || end.value() != 0) {
644                 ALOGW("Bad string block: last string is not 0-terminated\n");
645                 return (mError=BAD_TYPE);
646             }
647         }
648     } else {
649         mStrings = NULL;
650         mStringPoolSize = 0;
651     }
652 
653     if (mHeader->styleCount > 0) {
654         mEntryStyles = mEntries + mHeader->stringCount;
655         // invariant: integer overflow in calculating mEntryStyles
656         if (mEntryStyles < mEntries) {
657             ALOGW("Bad string block: integer overflow finding styles\n");
658             return (mError=BAD_TYPE);
659         }
660 
661         if ((mEntryStyles.convert<uint8_t>() - mHeader.convert<uint8_t>()) > (int)size) {
662             ALOGW("Bad string block: entry of %d styles extends past data size %d\n",
663                     (int)(mEntryStyles.convert<uint8_t>()-mHeader.convert<uint8_t>()),
664                     (int)size);
665             return (mError=BAD_TYPE);
666         }
667         mStyles = data.offset(mHeader->stylesStart).convert<uint32_t>();
668         if (mHeader->stylesStart >= mHeader->header.size) {
669             ALOGW("Bad string block: style pool starts %d, after total size %d\n",
670                     (int)mHeader->stylesStart, (int)mHeader->header.size);
671             return (mError=BAD_TYPE);
672         }
673         mStylePoolSize =
674             (mHeader->header.size-mHeader->stylesStart)/sizeof(uint32_t);
675 
676         if (notDeviceEndian) {
677             size_t i;
678             uint32_t* e = const_cast<uint32_t*>(mEntryStyles.unsafe_ptr());
679             for (i=0; i<mHeader->styleCount; i++) {
680                 e[i] = dtohl(e[i]);
681             }
682             uint32_t* s = const_cast<uint32_t*>(mStyles.unsafe_ptr());
683             for (i=0; i<mStylePoolSize; i++) {
684                 s[i] = dtohl(s[i]);
685             }
686         }
687 
688         const ResStringPool_span endSpan = {
689             { htodl(ResStringPool_span::END) },
690             htodl(ResStringPool_span::END), htodl(ResStringPool_span::END)
691         };
692 
693         auto stylesEnd = mStyles + (mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t)));
694         if (!stylesEnd || memcmp(stylesEnd.unsafe_ptr(), &endSpan, sizeof(endSpan)) != 0) {
695             ALOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
696             return (mError=BAD_TYPE);
697         }
698     } else {
699         mEntryStyles = NULL;
700         mStyles = NULL;
701         mStylePoolSize = 0;
702     }
703 
704     if (mIndexLookupCache) {
705       if ((mHeader->flags & ResStringPool_header::UTF8_FLAG) != 0) {
706         mIndexLookupCache->first.reserve(mHeader->stringCount);
707       } else {
708         mIndexLookupCache->second.reserve(mHeader->stringCount);
709       }
710     }
711 
712     return (mError=NO_ERROR);
713 }
714 
getError() const715 status_t ResStringPool::getError() const
716 {
717     return mError;
718 }
719 
uninit()720 void ResStringPool::uninit()
721 {
722     mError = NO_INIT;
723     if (mHeader && mCache != NULL) {
724         for (size_t x = 0; x < mHeader->stringCount; x++) {
725             if (mCache[x] != NULL) {
726                 free(mCache[x]);
727                 mCache[x] = NULL;
728             }
729         }
730         free(mCache);
731         mCache = NULL;
732     }
733     if (mOwnedData) {
734         free(mOwnedData);
735         mOwnedData = NULL;
736     }
737     if (mIndexLookupCache) {
738       mIndexLookupCache->first.clear();
739       mIndexLookupCache->second.clear();
740     }
741 }
742 
743 /**
744  * Strings in UTF-16 format have length indicated by a length encoded in the
745  * stored data. It is either 1 or 2 characters of length data. This allows a
746  * maximum length of 0x7FFFFFF (2147483647 bytes), but if you're storing that
747  * much data in a string, you're abusing them.
748  *
749  * If the high bit is set, then there are two characters or 4 bytes of length
750  * data encoded. In that case, drop the high bit of the first character and
751  * add it together with the next character.
752  */
decodeLength(incfs::map_ptr<uint16_t> * str)753 static inline base::expected<size_t, IOError> decodeLength(incfs::map_ptr<uint16_t>* str)
754 {
755     if (UNLIKELY(!*str)) {
756         return base::unexpected(IOError::PAGES_MISSING);
757     }
758 
759     size_t len = str->value();
760     if ((len & 0x8000U) != 0) {
761         ++(*str);
762         if (UNLIKELY(!*str)) {
763             return base::unexpected(IOError::PAGES_MISSING);
764         }
765         len = ((len & 0x7FFFU) << 16U) | str->value();
766     }
767     ++(*str);
768     return len;
769 }
770 
771 /**
772  * Strings in UTF-8 format have length indicated by a length encoded in the
773  * stored data. It is either 1 or 2 characters of length data. This allows a
774  * maximum length of 0x7FFF (32767 bytes), but you should consider storing
775  * text in another way if you're using that much data in a single string.
776  *
777  * If the high bit is set, then there are two characters or 2 bytes of length
778  * data encoded. In that case, drop the high bit of the first character and
779  * add it together with the next character.
780  */
decodeLength(incfs::map_ptr<uint8_t> * str)781 static inline base::expected<size_t, IOError> decodeLength(incfs::map_ptr<uint8_t>* str)
782 {
783     if (UNLIKELY(!*str)) {
784         return base::unexpected(IOError::PAGES_MISSING);
785     }
786 
787     size_t len = str->value();
788     if ((len & 0x80U) != 0) {
789         ++(*str);
790         if (UNLIKELY(!*str)) {
791             return base::unexpected(IOError::PAGES_MISSING);
792         }
793         len = ((len & 0x7FU) << 8U) | str->value();
794     }
795     ++(*str);
796     return len;
797 }
798 
stringAt(size_t idx) const799 base::expected<StringPiece16, NullOrIOError> ResStringPool::stringAt(size_t idx) const
800 {
801     if (mError == NO_ERROR && idx < mHeader->stringCount) {
802         const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
803         auto offPtr = mEntries + idx;
804         if (UNLIKELY(!offPtr)) {
805            return base::unexpected(IOError::PAGES_MISSING);
806         }
807 
808         const uint32_t off = (offPtr.value())/(isUTF8?sizeof(uint8_t):sizeof(uint16_t));
809         if (off < (mStringPoolSize-1)) {
810             if (!isUTF8) {
811                 auto strings = mStrings.convert<uint16_t>();
812                 auto str = strings+off;
813 
814                 const base::expected<size_t, IOError> u16len = decodeLength(&str);
815                 if (UNLIKELY(!u16len.has_value())) {
816                     return base::unexpected(u16len.error());
817                 }
818 
819                 if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) {
820                     // Reject malformed (non null-terminated) strings
821                     const auto nullAddress = str + (*u16len);
822                     if (UNLIKELY(!nullAddress)) {
823                        return base::unexpected(IOError::PAGES_MISSING);
824                     }
825 
826                     if (nullAddress.value() != 0x0000) {
827                         ALOGW("Bad string block: string #%d is not null-terminated", (int)idx);
828                         return base::unexpected(std::nullopt);
829                     }
830 
831                     if (UNLIKELY(!str.verify(*u16len + 1U))) {
832                       return base::unexpected(IOError::PAGES_MISSING);
833                     }
834 
835                     return StringPiece16(reinterpret_cast<const char16_t*>(str.unsafe_ptr()),
836                                          *u16len);
837                 } else {
838                     ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
839                             (int)idx, (int)(str+*u16len-strings), (int)mStringPoolSize);
840                 }
841             } else {
842                 auto strings = mStrings.convert<uint8_t>();
843                 auto u8str = strings+off;
844 
845                 base::expected<size_t, IOError> u16len = decodeLength(&u8str);
846                 if (UNLIKELY(!u16len.has_value())) {
847                     return base::unexpected(u16len.error());
848                 }
849 
850                 const base::expected<size_t, IOError> u8len = decodeLength(&u8str);
851                 if (UNLIKELY(!u8len.has_value())) {
852                     return base::unexpected(u8len.error());
853                 }
854 
855                 // encLen must be less than 0x7FFF due to encoding.
856                 if ((uint32_t)(u8str+*u8len-strings) < mStringPoolSize) {
857                   AutoMutex lock(mCachesLock);
858 
859                   if (mCache != NULL && mCache[idx] != NULL) {
860                     return StringPiece16(mCache[idx], *u16len);
861                   }
862 
863                     // Retrieve the actual length of the utf8 string if the
864                     // encoded length was truncated
865                     auto decodedString = stringDecodeAt(idx, u8str, *u8len);
866                     if (!decodedString.has_value()) {
867                         return base::unexpected(decodedString.error());
868                     }
869 
870                     // Since AAPT truncated lengths longer than 0x7FFF, check
871                     // that the bits that remain after truncation at least match
872                     // the bits of the actual length
873                     ssize_t actualLen = utf8_to_utf16_length(
874                         reinterpret_cast<const uint8_t*>(decodedString->data()),
875                         decodedString->size());
876 
877                     if (actualLen < 0 || ((size_t)actualLen & 0x7FFFU) != *u16len) {
878                         ALOGW("Bad string block: string #%lld decoded length is not correct "
879                                 "%lld vs %llu\n",
880                                 (long long)idx, (long long)actualLen, (long long)*u16len);
881                         return base::unexpected(std::nullopt);
882                     }
883 
884                     u16len = (size_t) actualLen;
885                     auto u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t));
886                     if (!u16str) {
887                         ALOGW("No memory when trying to allocate decode cache for string #%d\n",
888                                 (int)idx);
889                         return base::unexpected(std::nullopt);
890                     }
891 
892                     utf8_to_utf16(reinterpret_cast<const uint8_t*>(decodedString->data()),
893                                   decodedString->size(), u16str, *u16len + 1);
894 
895                     if (mCache == NULL) {
896 #ifndef __ANDROID__
897                         if (kDebugStringPoolNoisy) {
898                             ALOGI("CREATING STRING CACHE OF %zu bytes",
899                                   mHeader->stringCount*sizeof(char16_t**));
900                         }
901 #else
902                         // We do not want to be in this case when actually running Android.
903                         ALOGW("CREATING STRING CACHE OF %zu bytes",
904                                 static_cast<size_t>(mHeader->stringCount*sizeof(char16_t**)));
905 #endif
906                         mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t*));
907                         if (mCache == NULL) {
908                             ALOGW("No memory trying to allocate decode cache table of %d bytes\n",
909                                   (int)(mHeader->stringCount*sizeof(char16_t**)));
910                             return base::unexpected(std::nullopt);
911                         }
912                     }
913 
914                     if (kDebugStringPoolNoisy) {
915                       ALOGI("Caching UTF8 string: %s", u8str.unsafe_ptr());
916                     }
917 
918                     mCache[idx] = u16str;
919                     return StringPiece16(u16str, *u16len);
920                 } else {
921                     ALOGW("Bad string block: string #%lld extends to %lld, past end at %lld\n",
922                             (long long)idx, (long long)(u8str+*u8len-strings),
923                             (long long)mStringPoolSize);
924                 }
925             }
926         } else {
927             ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
928                     (int)idx, (int)(off*sizeof(uint16_t)),
929                     (int)(mStringPoolSize*sizeof(uint16_t)));
930         }
931     }
932     return base::unexpected(std::nullopt);
933 }
934 
string8At(size_t idx) const935 base::expected<StringPiece, NullOrIOError> ResStringPool::string8At(size_t idx) const
936 {
937     if (mError == NO_ERROR && idx < mHeader->stringCount) {
938         if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) == 0) {
939             return base::unexpected(std::nullopt);
940         }
941 
942         auto offPtr = mEntries + idx;
943         if (UNLIKELY(!offPtr)) {
944            return base::unexpected(IOError::PAGES_MISSING);
945         }
946 
947         const uint32_t off = (offPtr.value())/sizeof(char);
948         if (off < (mStringPoolSize-1)) {
949             auto strings = mStrings.convert<uint8_t>();
950             auto str = strings+off;
951 
952             // Decode the UTF-16 length. This is not used if we're not
953             // converting to UTF-16 from UTF-8.
954             const base::expected<size_t, IOError> u16len = decodeLength(&str);
955             if (UNLIKELY(!u16len.has_value())) {
956                 return base::unexpected(u16len.error());
957             }
958 
959             const base::expected<size_t, IOError> u8len = decodeLength(&str);
960             if (UNLIKELY(!u8len.has_value())) {
961                 return base::unexpected(u8len.error());
962             }
963 
964             if ((uint32_t)(str+*u8len-strings) < mStringPoolSize) {
965                 return stringDecodeAt(idx, str, *u8len);
966             } else {
967                 ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
968                         (int)idx, (int)(str+*u8len-strings), (int)mStringPoolSize);
969             }
970         } else {
971             ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
972                     (int)idx, (int)(off*sizeof(uint16_t)),
973                     (int)(mStringPoolSize*sizeof(uint16_t)));
974         }
975     }
976     return base::unexpected(std::nullopt);
977 }
978 
979 /**
980  * AAPT incorrectly writes a truncated string length when the string size
981  * exceeded the maximum possible encode length value (0x7FFF). To decode a
982  * truncated length, iterate through length values that end in the encode length
983  * bits. Strings that exceed the maximum encode length are not placed into
984  * StringPools in AAPT2.
985  **/
stringDecodeAt(size_t idx,incfs::map_ptr<uint8_t> str,size_t encLen) const986 base::expected<StringPiece, NullOrIOError> ResStringPool::stringDecodeAt(
987       size_t idx, incfs::map_ptr<uint8_t> str, size_t encLen) const
988 {
989     const auto strings = mStrings.convert<uint8_t>();
990     size_t i = 0, end = encLen;
991     while ((uint32_t)(str+end-strings) < mStringPoolSize) {
992         const auto nullAddress = str + end;
993         if (UNLIKELY(!nullAddress)) {
994             return base::unexpected(IOError::PAGES_MISSING);
995         }
996 
997         if (nullAddress.value() == 0x00) {
998             if (i != 0) {
999                 ALOGW("Bad string block: string #%d is truncated (actual length is %d)",
1000                       (int)idx, (int)end);
1001             }
1002 
1003             if (UNLIKELY(!str.verify(end + 1U))) {
1004               return base::unexpected(IOError::PAGES_MISSING);
1005             }
1006 
1007             return StringPiece((const char*) str.unsafe_ptr(), end);
1008         }
1009 
1010         end = (++i << (sizeof(uint8_t) * 8 * 2 - 1)) | encLen;
1011     }
1012 
1013     // Reject malformed (non null-terminated) strings
1014     ALOGW("Bad string block: string #%d is not null-terminated", (int)idx);
1015     return base::unexpected(std::nullopt);
1016 }
1017 
string8ObjectAt(size_t idx) const1018 base::expected<String8, IOError> ResStringPool::string8ObjectAt(size_t idx) const
1019 {
1020     const base::expected<StringPiece, NullOrIOError> str = string8At(idx);
1021     if (UNLIKELY(IsIOError(str))) {
1022         return base::unexpected(GetIOError(str.error()));
1023     }
1024     if (str.has_value()) {
1025         return String8(str->data(), str->size());
1026     }
1027 
1028     const base::expected<StringPiece16, NullOrIOError> str16 = stringAt(idx);
1029     if (UNLIKELY(IsIOError(str16))) {
1030         return base::unexpected(GetIOError(str16.error()));
1031     }
1032     if (str16.has_value()) {
1033         return String8(str16->data(), str16->size());
1034     }
1035 
1036     return String8();
1037 }
1038 
styleAt(const ResStringPool_ref & ref) const1039 base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> ResStringPool::styleAt(
1040     const ResStringPool_ref& ref) const
1041 {
1042     return styleAt(ref.index);
1043 }
1044 
styleAt(size_t idx) const1045 base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> ResStringPool::styleAt(
1046     size_t idx) const
1047 {
1048     if (mError == NO_ERROR && idx < mHeader->styleCount) {
1049         auto offPtr = mEntryStyles + idx;
1050         if (UNLIKELY(!offPtr)) {
1051            return base::unexpected(IOError::PAGES_MISSING);
1052         }
1053 
1054         const uint32_t off = ((offPtr.value())/sizeof(uint32_t));
1055         if (off < mStylePoolSize) {
1056             return (mStyles+off).convert<ResStringPool_span>();
1057         } else {
1058             ALOGW("Bad string block: style #%d entry is at %d, past end at %d\n",
1059                     (int)idx, (int)(off*sizeof(uint32_t)),
1060                     (int)(mStylePoolSize*sizeof(uint32_t)));
1061         }
1062     }
1063     return base::unexpected(std::nullopt);
1064 }
1065 
indexOfString(const char16_t * str,size_t strLen) const1066 base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_t* str,
1067                                                                    size_t strLen) const
1068 {
1069     if (mError != NO_ERROR) {
1070         return base::unexpected(std::nullopt);
1071     }
1072 
1073     if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
1074         if (kDebugStringPoolNoisy) {
1075             ALOGI("indexOfString UTF-8: %s", String8(str, strLen).c_str());
1076         }
1077 
1078         // The string pool contains UTF 8 strings; we don't want to cause
1079         // temporary UTF-16 strings to be created as we search.
1080         if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
1081             // Do a binary search for the string...  this is a little tricky,
1082             // because the strings are sorted with strzcmp16().  So to match
1083             // the ordering, we need to convert strings in the pool to UTF-16.
1084             // But we don't want to hit the cache, so instead we will have a
1085             // local temporary allocation for the conversions.
1086             size_t convBufferLen = strLen + 4;
1087             std::vector<char16_t> convBuffer(convBufferLen);
1088             ssize_t l = 0;
1089             ssize_t h = mHeader->stringCount-1;
1090 
1091             ssize_t mid;
1092             while (l <= h) {
1093                 mid = l + (h - l)/2;
1094                 int c = -1;
1095                 const base::expected<StringPiece, NullOrIOError> s = string8At(mid);
1096                 if (UNLIKELY(IsIOError(s))) {
1097                     return base::unexpected(s.error());
1098                 }
1099                 if (s.has_value()) {
1100                     char16_t* end = utf8_to_utf16(reinterpret_cast<const uint8_t*>(s->data()),
1101                                                   s->size(), convBuffer.data(), convBufferLen);
1102                     c = strzcmp16(convBuffer.data(), end-convBuffer.data(), str, strLen);
1103                 }
1104                 if (kDebugStringPoolNoisy) {
1105                     ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
1106                           s->data(), c, (int)l, (int)mid, (int)h);
1107                 }
1108                 if (c == 0) {
1109                     if (kDebugStringPoolNoisy) {
1110                         ALOGI("MATCH!");
1111                     }
1112                     return mid;
1113                 } else if (c < 0) {
1114                     l = mid + 1;
1115                 } else {
1116                     h = mid - 1;
1117                 }
1118             }
1119         } else {
1120             // It is unusual to get the ID from an unsorted string block...
1121             // most often this happens because we want to get IDs for style
1122             // span tags; since those always appear at the end of the string
1123             // block, start searching at the back.
1124             String8 str8(str, strLen);
1125             const size_t str8Len = str8.size();
1126             std::optional<AutoMutex> cacheLock;
1127             if (mIndexLookupCache) {
1128               cacheLock.emplace(mCachesLock);
1129               if (auto it = mIndexLookupCache->first.find(std::string_view(str8));
1130                   it != mIndexLookupCache->first.end()) {
1131                 return it->second;
1132               }
1133             }
1134 
1135             for (int i=mHeader->stringCount-1; i>=0; i--) {
1136                 const base::expected<StringPiece, NullOrIOError> s = string8At(i);
1137                 if (UNLIKELY(IsIOError(s))) {
1138                     return base::unexpected(s.error());
1139                 }
1140                 if (s.has_value()) {
1141                   if (mIndexLookupCache) {
1142                     mIndexLookupCache->first.insert({*s, i});
1143                   }
1144                     if (kDebugStringPoolNoisy) {
1145                         ALOGI("Looking at %s, i=%d\n", s->data(), i);
1146                     }
1147                     if (str8Len == s->size()
1148                             && memcmp(s->data(), str8.c_str(), str8Len) == 0) {
1149                         if (kDebugStringPoolNoisy) {
1150                             ALOGI("MATCH!");
1151                         }
1152                         return i;
1153                     }
1154                 }
1155             }
1156         }
1157 
1158     } else {
1159         if (kDebugStringPoolNoisy) {
1160             ALOGI("indexOfString UTF-16: %s", String8(str, strLen).c_str());
1161         }
1162 
1163         if (mHeader->flags&ResStringPool_header::SORTED_FLAG) {
1164             // Do a binary search for the string...
1165             ssize_t l = 0;
1166             ssize_t h = mHeader->stringCount-1;
1167 
1168             ssize_t mid;
1169             while (l <= h) {
1170                 mid = l + (h - l)/2;
1171                 const base::expected<StringPiece16, NullOrIOError> s = stringAt(mid);
1172                 if (UNLIKELY(IsIOError(s))) {
1173                     return base::unexpected(s.error());
1174                 }
1175                 int c = s.has_value() ? strzcmp16(s->data(), s->size(), str, strLen) : -1;
1176                 if (kDebugStringPoolNoisy) {
1177                     ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
1178                           String8(s->data(), s->size()).c_str(), c, (int)l, (int)mid, (int)h);
1179                 }
1180                 if (c == 0) {
1181                     if (kDebugStringPoolNoisy) {
1182                         ALOGI("MATCH!");
1183                     }
1184                     return mid;
1185                 } else if (c < 0) {
1186                     l = mid + 1;
1187                 } else {
1188                     h = mid - 1;
1189                 }
1190             }
1191         } else {
1192             // It is unusual to get the ID from an unsorted string block...
1193             // most often this happens because we want to get IDs for style
1194             // span tags; since those always appear at the end of the string
1195             // block, start searching at the back.
1196             std::optional<AutoMutex> cacheLock;
1197             if (mIndexLookupCache) {
1198               cacheLock.emplace(mCachesLock);
1199               if (auto it = mIndexLookupCache->second.find({str, strLen});
1200                   it != mIndexLookupCache->second.end()) {
1201                 return it->second;
1202               }
1203             }
1204             for (int i=mHeader->stringCount-1; i>=0; i--) {
1205                 const base::expected<StringPiece16, NullOrIOError> s = stringAt(i);
1206                 if (UNLIKELY(IsIOError(s))) {
1207                     return base::unexpected(s.error());
1208                 }
1209                 if (kDebugStringPoolNoisy) {
1210                   ALOGI("Looking16 at %s, i=%d\n", String8(s->data(), s->size()).c_str(), i);
1211                 }
1212                 if (s.has_value()) {
1213                   if (mIndexLookupCache) {
1214                     mIndexLookupCache->second.insert({*s, i});
1215                   }
1216                   if (strLen == s->size() && strzcmp16(s->data(), s->size(), str, strLen) == 0) {
1217                     if (kDebugStringPoolNoisy) {
1218                       ALOGI("MATCH16!");
1219                     }
1220                     return i;
1221                   }
1222                 }
1223             }
1224         }
1225     }
1226     return base::unexpected(std::nullopt);
1227 }
1228 
size() const1229 size_t ResStringPool::size() const
1230 {
1231     return (mError == NO_ERROR) ? mHeader->stringCount : 0;
1232 }
1233 
styleCount() const1234 size_t ResStringPool::styleCount() const
1235 {
1236     return (mError == NO_ERROR) ? mHeader->styleCount : 0;
1237 }
1238 
bytes() const1239 size_t ResStringPool::bytes() const
1240 {
1241     return (mError == NO_ERROR) ? mHeader->header.size : 0;
1242 }
1243 
data() const1244 incfs::map_ptr<void> ResStringPool::data() const
1245 {
1246 
1247     return mHeader.unsafe_ptr();
1248 }
1249 
isSorted() const1250 bool ResStringPool::isSorted() const
1251 {
1252     return (mHeader->flags&ResStringPool_header::SORTED_FLAG)!=0;
1253 }
1254 
isUTF8() const1255 bool ResStringPool::isUTF8() const
1256 {
1257     return (mHeader->flags&ResStringPool_header::UTF8_FLAG)!=0;
1258 }
1259 
1260 // --------------------------------------------------------------------
1261 // --------------------------------------------------------------------
1262 // --------------------------------------------------------------------
1263 
ResXMLParser(const ResXMLTree & tree)1264 ResXMLParser::ResXMLParser(const ResXMLTree& tree)
1265     : mTree(tree), mEventCode(BAD_DOCUMENT)
1266 {
1267 }
1268 
restart()1269 void ResXMLParser::restart()
1270 {
1271     mCurNode = NULL;
1272     mEventCode = mTree.mError == NO_ERROR ? START_DOCUMENT : BAD_DOCUMENT;
1273 }
getStrings() const1274 const ResStringPool& ResXMLParser::getStrings() const
1275 {
1276     return mTree.mStrings;
1277 }
1278 
getEventType() const1279 ResXMLParser::event_code_t ResXMLParser::getEventType() const
1280 {
1281     return mEventCode;
1282 }
1283 
next()1284 ResXMLParser::event_code_t ResXMLParser::next()
1285 {
1286     if (mEventCode == START_DOCUMENT) {
1287         mCurNode = mTree.mRootNode;
1288         mCurExt = mTree.mRootExt;
1289         return (mEventCode=mTree.mRootCode);
1290     } else if (mEventCode >= FIRST_CHUNK_CODE) {
1291         return nextNode();
1292     }
1293     return mEventCode;
1294 }
1295 
getCommentID() const1296 int32_t ResXMLParser::getCommentID() const
1297 {
1298     return mCurNode != NULL ? dtohl(mCurNode->comment.index) : -1;
1299 }
1300 
getComment(size_t * outLen) const1301 const char16_t* ResXMLParser::getComment(size_t* outLen) const
1302 {
1303     int32_t id = getCommentID();
1304     return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
1305 }
1306 
getLineNumber() const1307 uint32_t ResXMLParser::getLineNumber() const
1308 {
1309     return mCurNode != NULL ? dtohl(mCurNode->lineNumber) : -1;
1310 }
1311 
getTextID() const1312 int32_t ResXMLParser::getTextID() const
1313 {
1314     if (mEventCode == TEXT) {
1315         return dtohl(((const ResXMLTree_cdataExt*)mCurExt)->data.index);
1316     }
1317     return -1;
1318 }
1319 
getText(size_t * outLen) const1320 const char16_t* ResXMLParser::getText(size_t* outLen) const
1321 {
1322     int32_t id = getTextID();
1323     return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
1324 }
1325 
getTextValue(Res_value * outValue) const1326 ssize_t ResXMLParser::getTextValue(Res_value* outValue) const
1327 {
1328     if (mEventCode == TEXT) {
1329         outValue->copyFrom_dtoh(((const ResXMLTree_cdataExt*)mCurExt)->typedData);
1330         return sizeof(Res_value);
1331     }
1332     return BAD_TYPE;
1333 }
1334 
getNamespacePrefixID() const1335 int32_t ResXMLParser::getNamespacePrefixID() const
1336 {
1337     if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
1338         return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->prefix.index);
1339     }
1340     return -1;
1341 }
1342 
getNamespacePrefix(size_t * outLen) const1343 const char16_t* ResXMLParser::getNamespacePrefix(size_t* outLen) const
1344 {
1345     int32_t id = getNamespacePrefixID();
1346     //printf("prefix=%d  event=%p\n", id, mEventCode);
1347     return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
1348 }
1349 
getNamespaceUriID() const1350 int32_t ResXMLParser::getNamespaceUriID() const
1351 {
1352     if (mEventCode == START_NAMESPACE || mEventCode == END_NAMESPACE) {
1353         return dtohl(((const ResXMLTree_namespaceExt*)mCurExt)->uri.index);
1354     }
1355     return -1;
1356 }
1357 
getNamespaceUri(size_t * outLen) const1358 const char16_t* ResXMLParser::getNamespaceUri(size_t* outLen) const
1359 {
1360     int32_t id = getNamespaceUriID();
1361     //printf("uri=%d  event=%p\n", id, mEventCode);
1362     return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
1363 }
1364 
getElementNamespaceID() const1365 int32_t ResXMLParser::getElementNamespaceID() const
1366 {
1367     if (mEventCode == START_TAG) {
1368         return dtohl(((const ResXMLTree_attrExt*)mCurExt)->ns.index);
1369     }
1370     if (mEventCode == END_TAG) {
1371         return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->ns.index);
1372     }
1373     return -1;
1374 }
1375 
getElementNamespace(size_t * outLen) const1376 const char16_t* ResXMLParser::getElementNamespace(size_t* outLen) const
1377 {
1378     int32_t id = getElementNamespaceID();
1379     return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
1380 }
1381 
getElementNameID() const1382 int32_t ResXMLParser::getElementNameID() const
1383 {
1384     if (mEventCode == START_TAG) {
1385         return dtohl(((const ResXMLTree_attrExt*)mCurExt)->name.index);
1386     }
1387     if (mEventCode == END_TAG) {
1388         return dtohl(((const ResXMLTree_endElementExt*)mCurExt)->name.index);
1389     }
1390     return -1;
1391 }
1392 
getElementName(size_t * outLen) const1393 const char16_t* ResXMLParser::getElementName(size_t* outLen) const
1394 {
1395     int32_t id = getElementNameID();
1396     return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
1397 }
1398 
getAttributeCount() const1399 size_t ResXMLParser::getAttributeCount() const
1400 {
1401     if (mEventCode == START_TAG) {
1402         return dtohs(((const ResXMLTree_attrExt*)mCurExt)->attributeCount);
1403     }
1404     return 0;
1405 }
1406 
getAttributeNamespaceID(size_t idx) const1407 int32_t ResXMLParser::getAttributeNamespaceID(size_t idx) const
1408 {
1409     if (mEventCode == START_TAG) {
1410         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
1411         if (idx < dtohs(tag->attributeCount)) {
1412             const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
1413                 (((const uint8_t*)tag)
1414                  + dtohs(tag->attributeStart)
1415                  + (dtohs(tag->attributeSize)*idx));
1416             return dtohl(attr->ns.index);
1417         }
1418     }
1419     return -2;
1420 }
1421 
getAttributeNamespace(size_t idx,size_t * outLen) const1422 const char16_t* ResXMLParser::getAttributeNamespace(size_t idx, size_t* outLen) const
1423 {
1424     int32_t id = getAttributeNamespaceID(idx);
1425     //printf("attribute namespace=%d  idx=%d  event=%p\n", id, idx, mEventCode);
1426     if (kDebugXMLNoisy) {
1427         printf("getAttributeNamespace 0x%zx=0x%x\n", idx, id);
1428     }
1429     return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
1430 }
1431 
getAttributeNamespace8(size_t idx,size_t * outLen) const1432 const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) const
1433 {
1434     int32_t id = getAttributeNamespaceID(idx);
1435     //printf("attribute namespace=%d  idx=%d  event=%p\n", id, idx, mEventCode);
1436     if (kDebugXMLNoisy) {
1437         printf("getAttributeNamespace 0x%zx=0x%x\n", idx, id);
1438     }
1439     return id >= 0 ? UnpackOptionalString(mTree.mStrings.string8At(id), outLen) : NULL;
1440 }
1441 
getAttributeNameID(size_t idx) const1442 int32_t ResXMLParser::getAttributeNameID(size_t idx) const
1443 {
1444     if (mEventCode == START_TAG) {
1445         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
1446         if (idx < dtohs(tag->attributeCount)) {
1447             const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
1448                 (((const uint8_t*)tag)
1449                  + dtohs(tag->attributeStart)
1450                  + (dtohs(tag->attributeSize)*idx));
1451             return dtohl(attr->name.index);
1452         }
1453     }
1454     return -1;
1455 }
1456 
getAttributeName(size_t idx,size_t * outLen) const1457 const char16_t* ResXMLParser::getAttributeName(size_t idx, size_t* outLen) const
1458 {
1459     int32_t id = getAttributeNameID(idx);
1460     //printf("attribute name=%d  idx=%d  event=%p\n", id, idx, mEventCode);
1461     if (kDebugXMLNoisy) {
1462         printf("getAttributeName 0x%zx=0x%x\n", idx, id);
1463     }
1464     return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
1465 }
1466 
getAttributeName8(size_t idx,size_t * outLen) const1467 const char* ResXMLParser::getAttributeName8(size_t idx, size_t* outLen) const
1468 {
1469     int32_t id = getAttributeNameID(idx);
1470     //printf("attribute name=%d  idx=%d  event=%p\n", id, idx, mEventCode);
1471     if (kDebugXMLNoisy) {
1472         printf("getAttributeName 0x%zx=0x%x\n", idx, id);
1473     }
1474     return id >= 0 ? UnpackOptionalString(mTree.mStrings.string8At(id), outLen) : NULL;
1475 }
1476 
getAttributeNameResID(size_t idx) const1477 uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
1478 {
1479     int32_t id = getAttributeNameID(idx);
1480     if (id >= 0 && (size_t)id < mTree.mNumResIds) {
1481         uint32_t resId = dtohl(mTree.mResIds[id]);
1482         if (mTree.mDynamicRefTable != NULL) {
1483             mTree.mDynamicRefTable->lookupResourceId(&resId);
1484         }
1485         return resId;
1486     }
1487     return 0;
1488 }
1489 
getAttributeValueStringID(size_t idx) const1490 int32_t ResXMLParser::getAttributeValueStringID(size_t idx) const
1491 {
1492     if (mEventCode == START_TAG) {
1493         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
1494         if (idx < dtohs(tag->attributeCount)) {
1495             const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
1496                 (((const uint8_t*)tag)
1497                  + dtohs(tag->attributeStart)
1498                  + (dtohs(tag->attributeSize)*idx));
1499             return dtohl(attr->rawValue.index);
1500         }
1501     }
1502     return -1;
1503 }
1504 
getAttributeStringValue(size_t idx,size_t * outLen) const1505 const char16_t* ResXMLParser::getAttributeStringValue(size_t idx, size_t* outLen) const
1506 {
1507     int32_t id = getAttributeValueStringID(idx);
1508     if (kDebugXMLNoisy) {
1509         printf("getAttributeValue 0x%zx=0x%x\n", idx, id);
1510     }
1511     return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
1512 }
1513 
getAttributeDataType(size_t idx) const1514 int32_t ResXMLParser::getAttributeDataType(size_t idx) const
1515 {
1516     if (mEventCode == START_TAG) {
1517         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
1518         if (idx < dtohs(tag->attributeCount)) {
1519             const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
1520                 (((const uint8_t*)tag)
1521                  + dtohs(tag->attributeStart)
1522                  + (dtohs(tag->attributeSize)*idx));
1523             uint8_t type = attr->typedValue.dataType;
1524             if (type != Res_value::TYPE_DYNAMIC_REFERENCE) {
1525                 return type;
1526             }
1527 
1528             // This is a dynamic reference. We adjust those references
1529             // to regular references at this level, so lie to the caller.
1530             return Res_value::TYPE_REFERENCE;
1531         }
1532     }
1533     return Res_value::TYPE_NULL;
1534 }
1535 
getAttributeData(size_t idx) const1536 int32_t ResXMLParser::getAttributeData(size_t idx) const
1537 {
1538     if (mEventCode == START_TAG) {
1539         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
1540         if (idx < dtohs(tag->attributeCount)) {
1541             const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
1542                 (((const uint8_t*)tag)
1543                  + dtohs(tag->attributeStart)
1544                  + (dtohs(tag->attributeSize)*idx));
1545             if (mTree.mDynamicRefTable == NULL ||
1546                     !mTree.mDynamicRefTable->requiresLookup(&attr->typedValue)) {
1547                 return dtohl(attr->typedValue.data);
1548             }
1549             uint32_t data = dtohl(attr->typedValue.data);
1550             if (mTree.mDynamicRefTable->lookupResourceId(&data) == NO_ERROR) {
1551                 return data;
1552             }
1553         }
1554     }
1555     return 0;
1556 }
1557 
getAttributeValue(size_t idx,Res_value * outValue) const1558 ssize_t ResXMLParser::getAttributeValue(size_t idx, Res_value* outValue) const
1559 {
1560     if (mEventCode == START_TAG) {
1561         const ResXMLTree_attrExt* tag = (const ResXMLTree_attrExt*)mCurExt;
1562         if (idx < dtohs(tag->attributeCount)) {
1563             const ResXMLTree_attribute* attr = (const ResXMLTree_attribute*)
1564                 (((const uint8_t*)tag)
1565                  + dtohs(tag->attributeStart)
1566                  + (dtohs(tag->attributeSize)*idx));
1567             outValue->copyFrom_dtoh(attr->typedValue);
1568             if (mTree.mDynamicRefTable != NULL &&
1569                     mTree.mDynamicRefTable->lookupResourceValue(outValue) != NO_ERROR) {
1570                 return BAD_TYPE;
1571             }
1572             return sizeof(Res_value);
1573         }
1574     }
1575     return BAD_TYPE;
1576 }
1577 
indexOfAttribute(const char * ns,const char * attr) const1578 ssize_t ResXMLParser::indexOfAttribute(const char* ns, const char* attr) const
1579 {
1580     String16 nsStr(ns != NULL ? ns : "");
1581     String16 attrStr(attr);
1582     return indexOfAttribute(ns ? nsStr.c_str() : NULL, ns ? nsStr.size() : 0,
1583                             attrStr.c_str(), attrStr.size());
1584 }
1585 
indexOfAttribute(const char16_t * ns,size_t nsLen,const char16_t * attr,size_t attrLen) const1586 ssize_t ResXMLParser::indexOfAttribute(const char16_t* ns, size_t nsLen,
1587                                        const char16_t* attr, size_t attrLen) const
1588 {
1589     if (mEventCode == START_TAG) {
1590         if (attr == NULL) {
1591             return NAME_NOT_FOUND;
1592         }
1593         const size_t N = getAttributeCount();
1594         if (mTree.mStrings.isUTF8()) {
1595             String8 ns8, attr8;
1596             if (ns != NULL) {
1597                 ns8 = String8(ns, nsLen);
1598             }
1599             attr8 = String8(attr, attrLen);
1600             if (kDebugStringPoolNoisy) {
1601                 ALOGI("indexOfAttribute UTF8 %s (%zu) / %s (%zu)", ns8.c_str(), nsLen,
1602                         attr8.c_str(), attrLen);
1603             }
1604             for (size_t i=0; i<N; i++) {
1605                 size_t curNsLen = 0, curAttrLen = 0;
1606                 const char* curNs = getAttributeNamespace8(i, &curNsLen);
1607                 const char* curAttr = getAttributeName8(i, &curAttrLen);
1608                 if (kDebugStringPoolNoisy) {
1609                     ALOGI("  curNs=%s (%zu), curAttr=%s (%zu)", curNs, curNsLen, curAttr, curAttrLen);
1610                 }
1611                 if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
1612                         && memcmp(attr8.c_str(), curAttr, attrLen) == 0) {
1613                     if (ns == NULL) {
1614                         if (curNs == NULL) {
1615                             if (kDebugStringPoolNoisy) {
1616                                 ALOGI("  FOUND!");
1617                             }
1618                             return i;
1619                         }
1620                     } else if (curNs != NULL) {
1621                         //printf(" --> ns=%s, curNs=%s\n",
1622                         //       String8(ns).c_str(), String8(curNs).c_str());
1623                         if (memcmp(ns8.c_str(), curNs, nsLen) == 0) {
1624                             if (kDebugStringPoolNoisy) {
1625                                 ALOGI("  FOUND!");
1626                             }
1627                             return i;
1628                         }
1629                     }
1630                 }
1631             }
1632         } else {
1633             if (kDebugStringPoolNoisy) {
1634                 ALOGI("indexOfAttribute UTF16 %s (%zu) / %s (%zu)",
1635                         String8(ns, nsLen).c_str(), nsLen,
1636                         String8(attr, attrLen).c_str(), attrLen);
1637             }
1638             for (size_t i=0; i<N; i++) {
1639                 size_t curNsLen = 0, curAttrLen = 0;
1640                 const char16_t* curNs = getAttributeNamespace(i, &curNsLen);
1641                 const char16_t* curAttr = getAttributeName(i, &curAttrLen);
1642                 if (kDebugStringPoolNoisy) {
1643                     ALOGI("  curNs=%s (%zu), curAttr=%s (%zu)",
1644                             String8(curNs, curNsLen).c_str(), curNsLen,
1645                             String8(curAttr, curAttrLen).c_str(), curAttrLen);
1646                 }
1647                 if (curAttr != NULL && curNsLen == nsLen && curAttrLen == attrLen
1648                         && (memcmp(attr, curAttr, attrLen*sizeof(char16_t)) == 0)) {
1649                     if (ns == NULL) {
1650                         if (curNs == NULL) {
1651                             if (kDebugStringPoolNoisy) {
1652                                 ALOGI("  FOUND!");
1653                             }
1654                             return i;
1655                         }
1656                     } else if (curNs != NULL) {
1657                         //printf(" --> ns=%s, curNs=%s\n",
1658                         //       String8(ns).c_str(), String8(curNs).c_str());
1659                         if (memcmp(ns, curNs, nsLen*sizeof(char16_t)) == 0) {
1660                             if (kDebugStringPoolNoisy) {
1661                                 ALOGI("  FOUND!");
1662                             }
1663                             return i;
1664                         }
1665                     }
1666                 }
1667             }
1668         }
1669     }
1670 
1671     return NAME_NOT_FOUND;
1672 }
1673 
indexOfID() const1674 ssize_t ResXMLParser::indexOfID() const
1675 {
1676     if (mEventCode == START_TAG) {
1677         const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->idIndex);
1678         if (idx > 0) return (idx-1);
1679     }
1680     return NAME_NOT_FOUND;
1681 }
1682 
indexOfClass() const1683 ssize_t ResXMLParser::indexOfClass() const
1684 {
1685     if (mEventCode == START_TAG) {
1686         const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->classIndex);
1687         if (idx > 0) return (idx-1);
1688     }
1689     return NAME_NOT_FOUND;
1690 }
1691 
indexOfStyle() const1692 ssize_t ResXMLParser::indexOfStyle() const
1693 {
1694     if (mEventCode == START_TAG) {
1695         const ssize_t idx = dtohs(((const ResXMLTree_attrExt*)mCurExt)->styleIndex);
1696         if (idx > 0) return (idx-1);
1697     }
1698     return NAME_NOT_FOUND;
1699 }
1700 
nextNode()1701 ResXMLParser::event_code_t ResXMLParser::nextNode()
1702 {
1703     if (mEventCode < 0) {
1704         return mEventCode;
1705     }
1706 
1707     do {
1708         const ResXMLTree_node* next = (const ResXMLTree_node*)
1709             (((const uint8_t*)mCurNode) + dtohl(mCurNode->header.size));
1710         if (kDebugXMLNoisy) {
1711             ALOGI("Next node: prev=%p, next=%p\n", mCurNode, next);
1712         }
1713 
1714         if (((const uint8_t*)next) >= mTree.mDataEnd) {
1715             mCurNode = NULL;
1716             return (mEventCode=END_DOCUMENT);
1717         }
1718 
1719         if (mTree.validateNode(next) != NO_ERROR) {
1720             mCurNode = NULL;
1721             return (mEventCode=BAD_DOCUMENT);
1722         }
1723 
1724         mCurNode = next;
1725         const uint16_t headerSize = dtohs(next->header.headerSize);
1726         const uint32_t totalSize = dtohl(next->header.size);
1727         mCurExt = ((const uint8_t*)next) + headerSize;
1728         size_t minExtSize = 0;
1729         event_code_t eventCode = (event_code_t)dtohs(next->header.type);
1730         switch ((mEventCode=eventCode)) {
1731             case RES_XML_START_NAMESPACE_TYPE:
1732             case RES_XML_END_NAMESPACE_TYPE:
1733                 minExtSize = sizeof(ResXMLTree_namespaceExt);
1734                 break;
1735             case RES_XML_START_ELEMENT_TYPE:
1736                 minExtSize = sizeof(ResXMLTree_attrExt);
1737                 break;
1738             case RES_XML_END_ELEMENT_TYPE:
1739                 minExtSize = sizeof(ResXMLTree_endElementExt);
1740                 break;
1741             case RES_XML_CDATA_TYPE:
1742                 minExtSize = sizeof(ResXMLTree_cdataExt);
1743                 break;
1744             default:
1745                 ALOGW("Unknown XML block: header type %d in node at %d\n",
1746                      (int)dtohs(next->header.type),
1747                      (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)));
1748                 continue;
1749         }
1750 
1751         if ((totalSize-headerSize) < minExtSize) {
1752             ALOGW("Bad XML block: header type 0x%x in node at 0x%x has size %d, need %d\n",
1753                  (int)dtohs(next->header.type),
1754                  (int)(((const uint8_t*)next)-((const uint8_t*)mTree.mHeader)),
1755                  (int)(totalSize-headerSize), (int)minExtSize);
1756             return (mEventCode=BAD_DOCUMENT);
1757         }
1758 
1759         //printf("CurNode=%p, CurExt=%p, headerSize=%d, minExtSize=%d\n",
1760         //       mCurNode, mCurExt, headerSize, minExtSize);
1761 
1762         return eventCode;
1763     } while (true);
1764 }
1765 
getPosition(ResXMLParser::ResXMLPosition * pos) const1766 void ResXMLParser::getPosition(ResXMLParser::ResXMLPosition* pos) const
1767 {
1768     pos->eventCode = mEventCode;
1769     pos->curNode = mCurNode;
1770     pos->curExt = mCurExt;
1771 }
1772 
setPosition(const ResXMLParser::ResXMLPosition & pos)1773 void ResXMLParser::setPosition(const ResXMLParser::ResXMLPosition& pos)
1774 {
1775     mEventCode = pos.eventCode;
1776     mCurNode = pos.curNode;
1777     mCurExt = pos.curExt;
1778 }
1779 
setSourceResourceId(const uint32_t resId)1780 void ResXMLParser::setSourceResourceId(const uint32_t resId)
1781 {
1782     mSourceResourceId = resId;
1783 }
1784 
getSourceResourceId() const1785 uint32_t ResXMLParser::getSourceResourceId() const
1786 {
1787     return mSourceResourceId;
1788 }
1789 
1790 // --------------------------------------------------------------------
1791 
1792 static volatile int32_t gCount = 0;
1793 
ResXMLTree(std::shared_ptr<const DynamicRefTable> dynamicRefTable)1794 ResXMLTree::ResXMLTree(std::shared_ptr<const DynamicRefTable> dynamicRefTable)
1795     : ResXMLParser(*this)
1796     , mDynamicRefTable(std::move(dynamicRefTable))
1797     , mError(NO_INIT), mOwnedData(NULL)
1798 {
1799     if (kDebugResXMLTree) {
1800         ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
1801     }
1802     restart();
1803 }
1804 
ResXMLTree()1805 ResXMLTree::ResXMLTree()
1806     : ResXMLParser(*this)
1807     , mDynamicRefTable(nullptr)
1808     , mError(NO_INIT), mOwnedData(NULL)
1809 {
1810     if (kDebugResXMLTree) {
1811         ALOGI("Creating ResXMLTree %p #%d\n", this, android_atomic_inc(&gCount)+1);
1812     }
1813     restart();
1814 }
1815 
~ResXMLTree()1816 ResXMLTree::~ResXMLTree()
1817 {
1818     if (kDebugResXMLTree) {
1819         ALOGI("Destroying ResXMLTree in %p #%d\n", this, android_atomic_dec(&gCount)-1);
1820     }
1821     uninit();
1822 }
1823 
setTo(const void * data,size_t size,bool copyData)1824 status_t ResXMLTree::setTo(const void* data, size_t size, bool copyData)
1825 {
1826     const ResChunk_header* chunk = nullptr;
1827     const ResChunk_header* lastChunk = nullptr;
1828 
1829     uninit();
1830     mEventCode = START_DOCUMENT;
1831 
1832     if (!data || !size) {
1833         return (mError=BAD_TYPE);
1834     }
1835     if (size < sizeof(ResXMLTree_header)) {
1836         ALOGW("Bad XML block: total size %d is less than the header size %d\n",
1837               int(size), int(sizeof(ResXMLTree_header)));
1838         mError = BAD_TYPE;
1839         goto done;
1840     }
1841     if (copyData) {
1842         mOwnedData = malloc(size);
1843         if (mOwnedData == NULL) {
1844             return (mError=NO_MEMORY);
1845         }
1846         memcpy(mOwnedData, data, size);
1847         data = mOwnedData;
1848     }
1849 
1850     mHeader = (const ResXMLTree_header*)data;
1851     mSize = dtohl(mHeader->header.size);
1852     if (dtohs(mHeader->header.headerSize) > mSize || mSize > size) {
1853         ALOGW("Bad XML block: header size %d or total size %d is larger than data size %d\n",
1854              (int)dtohs(mHeader->header.headerSize),
1855              (int)dtohl(mHeader->header.size), (int)size);
1856         mError = BAD_TYPE;
1857         goto done;
1858     }
1859     if (dtohs(mHeader->header.type) != RES_XML_TYPE) {
1860         ALOGW("Bad XML block: expected root block type %d, got %d\n",
1861             int(RES_XML_TYPE), int(dtohs(mHeader->header.type)));
1862         mError = BAD_TYPE;
1863         goto done;
1864     }
1865 
1866     mDataEnd = ((const uint8_t*)mHeader) + mSize;
1867 
1868     mStrings.uninit();
1869     mRootNode = NULL;
1870     mResIds = NULL;
1871     mNumResIds = 0;
1872 
1873     // First look for a couple interesting chunks: the string block
1874     // and first XML node.
1875     chunk = (const ResChunk_header*)(((const uint8_t*)mHeader) + dtohs(mHeader->header.headerSize));
1876     lastChunk = chunk;
1877     while (((const uint8_t*)chunk) < (mDataEnd-sizeof(ResChunk_header)) &&
1878            ((const uint8_t*)chunk) < (mDataEnd-dtohl(chunk->size))) {
1879         status_t err = validate_chunk(chunk, sizeof(ResChunk_header), mDataEnd, "XML");
1880         if (err != NO_ERROR) {
1881             mError = err;
1882             goto done;
1883         }
1884         const uint16_t type = dtohs(chunk->type);
1885         const size_t size = dtohl(chunk->size);
1886         if (kDebugXMLNoisy) {
1887             printf("Scanning @ %p: type=0x%x, size=0x%zx\n",
1888                     (void*)(((uintptr_t)chunk)-((uintptr_t)mHeader)), type, size);
1889         }
1890         if (type == RES_STRING_POOL_TYPE) {
1891             mStrings.setTo(chunk, size);
1892         } else if (type == RES_XML_RESOURCE_MAP_TYPE) {
1893             mResIds = (const uint32_t*)
1894                 (((const uint8_t*)chunk)+dtohs(chunk->headerSize));
1895             mNumResIds = (dtohl(chunk->size)-dtohs(chunk->headerSize))/sizeof(uint32_t);
1896         } else if (type >= RES_XML_FIRST_CHUNK_TYPE
1897                    && type <= RES_XML_LAST_CHUNK_TYPE) {
1898             if (validateNode((const ResXMLTree_node*)chunk) != NO_ERROR) {
1899                 mError = BAD_TYPE;
1900                 goto done;
1901             }
1902             mCurNode = (const ResXMLTree_node*)lastChunk;
1903             if (nextNode() == BAD_DOCUMENT) {
1904                 mError = BAD_TYPE;
1905                 goto done;
1906             }
1907             mRootNode = mCurNode;
1908             mRootExt = mCurExt;
1909             mRootCode = mEventCode;
1910             break;
1911         } else {
1912             if (kDebugXMLNoisy) {
1913                 printf("Skipping unknown chunk!\n");
1914             }
1915         }
1916         lastChunk = chunk;
1917         chunk = (const ResChunk_header*)
1918             (((const uint8_t*)chunk) + size);
1919     }
1920 
1921     if (mRootNode == NULL) {
1922         ALOGW("Bad XML block: no root element node found\n");
1923         mError = BAD_TYPE;
1924         goto done;
1925     }
1926 
1927     mError = mStrings.getError();
1928 
1929 done:
1930     if (mError) {
1931         uninit();
1932     } else {
1933         restart();
1934     }
1935     return mError;
1936 }
1937 
getError() const1938 status_t ResXMLTree::getError() const
1939 {
1940     return mError;
1941 }
1942 
uninit()1943 void ResXMLTree::uninit()
1944 {
1945     mError = NO_INIT;
1946     mStrings.uninit();
1947     if (mOwnedData) {
1948         free(mOwnedData);
1949         mOwnedData = NULL;
1950     }
1951     restart();
1952 }
1953 
validateNode(const ResXMLTree_node * node) const1954 status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const
1955 {
1956     const uint16_t eventCode = dtohs(node->header.type);
1957 
1958     status_t err = validate_chunk(
1959         &node->header, sizeof(ResXMLTree_node),
1960         mDataEnd, "ResXMLTree_node");
1961 
1962     if (err >= NO_ERROR) {
1963         // Only perform additional validation on START nodes
1964         if (eventCode != RES_XML_START_ELEMENT_TYPE) {
1965             return NO_ERROR;
1966         }
1967 
1968         const uint16_t headerSize = dtohs(node->header.headerSize);
1969         const uint32_t size = dtohl(node->header.size);
1970         const ResXMLTree_attrExt* attrExt = (const ResXMLTree_attrExt*)
1971             (((const uint8_t*)node) + headerSize);
1972         // check for sensical values pulled out of the stream so far...
1973         if ((size >= headerSize + sizeof(ResXMLTree_attrExt))
1974                 && ((void*)attrExt > (void*)node)) {
1975             const size_t attrSize = ((size_t)dtohs(attrExt->attributeSize))
1976                 * dtohs(attrExt->attributeCount);
1977             if ((dtohs(attrExt->attributeStart)+attrSize) <= (size-headerSize)) {
1978                 return NO_ERROR;
1979             }
1980             ALOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
1981                     (unsigned int)(dtohs(attrExt->attributeStart)+attrSize),
1982                     (unsigned int)(size-headerSize));
1983         }
1984         else {
1985             ALOGW("Bad XML start block: node header size 0x%x, size 0x%x\n",
1986                 (unsigned int)headerSize, (unsigned int)size);
1987         }
1988         return BAD_TYPE;
1989     }
1990 
1991     return err;
1992 
1993 #if 0
1994     const bool isStart = dtohs(node->header.type) == RES_XML_START_ELEMENT_TYPE;
1995 
1996     const uint16_t headerSize = dtohs(node->header.headerSize);
1997     const uint32_t size = dtohl(node->header.size);
1998 
1999     if (headerSize >= (isStart ? sizeof(ResXMLTree_attrNode) : sizeof(ResXMLTree_node))) {
2000         if (size >= headerSize) {
2001             if (((const uint8_t*)node) <= (mDataEnd-size)) {
2002                 if (!isStart) {
2003                     return NO_ERROR;
2004                 }
2005                 if ((((size_t)dtohs(node->attributeSize))*dtohs(node->attributeCount))
2006                         <= (size-headerSize)) {
2007                     return NO_ERROR;
2008                 }
2009                 ALOGW("Bad XML block: node attributes use 0x%x bytes, only have 0x%x bytes\n",
2010                         ((int)dtohs(node->attributeSize))*dtohs(node->attributeCount),
2011                         (int)(size-headerSize));
2012                 return BAD_TYPE;
2013             }
2014             ALOGW("Bad XML block: node at 0x%x extends beyond data end 0x%x\n",
2015                     (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)), (int)mSize);
2016             return BAD_TYPE;
2017         }
2018         ALOGW("Bad XML block: node at 0x%x header size 0x%x smaller than total size 0x%x\n",
2019                 (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
2020                 (int)headerSize, (int)size);
2021         return BAD_TYPE;
2022     }
2023     ALOGW("Bad XML block: node at 0x%x header size 0x%x too small\n",
2024             (int)(((const uint8_t*)node)-((const uint8_t*)mHeader)),
2025             (int)headerSize);
2026     return BAD_TYPE;
2027 #endif
2028 }
2029 
2030 // --------------------------------------------------------------------
2031 // --------------------------------------------------------------------
2032 // --------------------------------------------------------------------
2033 
copyFromDeviceNoSwap(const ResTable_config & o)2034 void ResTable_config::copyFromDeviceNoSwap(const ResTable_config& o) {
2035     const size_t size = dtohl(o.size);
2036     if (size >= sizeof(ResTable_config)) {
2037         *this = o;
2038     } else {
2039         memcpy(this, &o, size);
2040         memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size);
2041     }
2042 }
2043 
unpackLanguageOrRegion(const char in[2],const char base,char out[4])2044 /* static */ size_t unpackLanguageOrRegion(const char in[2], const char base,
2045         char out[4]) {
2046   if (in[0] & 0x80) {
2047       // The high bit is "1", which means this is a packed three letter
2048       // language code.
2049 
2050       // The smallest 5 bits of the second char are the first alphabet.
2051       const uint8_t first = in[1] & 0x1f;
2052       // The last three bits of the second char and the first two bits
2053       // of the first char are the second alphabet.
2054       const uint8_t second = ((in[1] & 0xe0) >> 5) + ((in[0] & 0x03) << 3);
2055       // Bits 3 to 7 (inclusive) of the first char are the third alphabet.
2056       const uint8_t third = (in[0] & 0x7c) >> 2;
2057 
2058       out[0] = first + base;
2059       out[1] = second + base;
2060       out[2] = third + base;
2061       out[3] = 0;
2062 
2063       return 3;
2064   }
2065 
2066   if (in[0]) {
2067       memcpy(out, in, 2);
2068       memset(out + 2, 0, 2);
2069       return 2;
2070   }
2071 
2072   memset(out, 0, 4);
2073   return 0;
2074 }
2075 
packLanguageOrRegion(const char * in,const char base,char out[2])2076 /* static */ void packLanguageOrRegion(const char* in, const char base,
2077         char out[2]) {
2078   if (in[2] == 0 || in[2] == '-') {
2079       out[0] = in[0];
2080       out[1] = in[1];
2081   } else {
2082       uint8_t first = (in[0] - base) & 0x007f;
2083       uint8_t second = (in[1] - base) & 0x007f;
2084       uint8_t third = (in[2] - base) & 0x007f;
2085 
2086       out[0] = (0x80 | (third << 2) | (second >> 3));
2087       out[1] = ((second << 5) | first);
2088   }
2089 }
2090 
2091 
packLanguage(const char * language)2092 void ResTable_config::packLanguage(const char* language) {
2093     packLanguageOrRegion(language, 'a', this->language);
2094 }
2095 
packRegion(const char * region)2096 void ResTable_config::packRegion(const char* region) {
2097     packLanguageOrRegion(region, '0', this->country);
2098 }
2099 
unpackLanguage(char language[4]) const2100 size_t ResTable_config::unpackLanguage(char language[4]) const {
2101     return unpackLanguageOrRegion(this->language, 'a', language);
2102 }
2103 
unpackRegion(char region[4]) const2104 size_t ResTable_config::unpackRegion(char region[4]) const {
2105     return unpackLanguageOrRegion(this->country, '0', region);
2106 }
2107 
2108 
copyFromDtoH(const ResTable_config & o)2109 void ResTable_config::copyFromDtoH(const ResTable_config& o) {
2110     copyFromDeviceNoSwap(o);
2111     size = sizeof(ResTable_config);
2112     mcc = dtohs(mcc);
2113     mnc = dtohs(mnc);
2114     density = dtohs(density);
2115     screenWidth = dtohs(screenWidth);
2116     screenHeight = dtohs(screenHeight);
2117     sdkVersion = dtohs(sdkVersion);
2118     minorVersion = dtohs(minorVersion);
2119     smallestScreenWidthDp = dtohs(smallestScreenWidthDp);
2120     screenWidthDp = dtohs(screenWidthDp);
2121     screenHeightDp = dtohs(screenHeightDp);
2122 }
2123 
swapHtoD()2124 void ResTable_config::swapHtoD() {
2125     size = htodl(size);
2126     mcc = htods(mcc);
2127     mnc = htods(mnc);
2128     density = htods(density);
2129     screenWidth = htods(screenWidth);
2130     screenHeight = htods(screenHeight);
2131     sdkVersion = htods(sdkVersion);
2132     minorVersion = htods(minorVersion);
2133     smallestScreenWidthDp = htods(smallestScreenWidthDp);
2134     screenWidthDp = htods(screenWidthDp);
2135     screenHeightDp = htods(screenHeightDp);
2136 }
2137 
compareLocales(const ResTable_config & l,const ResTable_config & r)2138 /* static */ inline int compareLocales(const ResTable_config &l, const ResTable_config &r) {
2139     if (l.locale != r.locale) {
2140         return (l.locale > r.locale) ? 1 : -1;
2141     }
2142 
2143     // The language & region are equal, so compare the scripts, variants and
2144     // numbering systms in this order. Comparison of variants and numbering
2145     // systems should happen very infrequently (if at all.)
2146     // The comparison code relies on memcmp low-level optimizations that make it
2147     // more efficient than strncmp.
2148     const char emptyScript[sizeof(l.localeScript)] = {'\0', '\0', '\0', '\0'};
2149     const char *lScript = l.localeScriptWasComputed ? emptyScript : l.localeScript;
2150     const char *rScript = r.localeScriptWasComputed ? emptyScript : r.localeScript;
2151 
2152     int script = memcmp(lScript, rScript, sizeof(l.localeScript));
2153     if (script) {
2154         return script;
2155     }
2156 
2157     int variant = memcmp(l.localeVariant, r.localeVariant, sizeof(l.localeVariant));
2158     if (variant) {
2159         return variant;
2160     }
2161 
2162     return memcmp(l.localeNumberingSystem, r.localeNumberingSystem,
2163                   sizeof(l.localeNumberingSystem));
2164 }
2165 
compare(const ResTable_config & o) const2166 int ResTable_config::compare(const ResTable_config& o) const {
2167     if (imsi != o.imsi) {
2168         return (imsi > o.imsi) ? 1 : -1;
2169     }
2170 
2171     int32_t diff = compareLocales(*this, o);
2172     if (diff < 0) {
2173         return -1;
2174     }
2175     if (diff > 0) {
2176         return 1;
2177     }
2178 
2179     if (grammaticalInflection != o.grammaticalInflection) {
2180         return grammaticalInflection < o.grammaticalInflection ? -1 : 1;
2181     }
2182     if (screenType != o.screenType) {
2183         return (screenType > o.screenType) ? 1 : -1;
2184     }
2185     if (input != o.input) {
2186         return (input > o.input) ? 1 : -1;
2187     }
2188     if (screenSize != o.screenSize) {
2189         return (screenSize > o.screenSize) ? 1 : -1;
2190     }
2191     if (version != o.version) {
2192         return (version > o.version) ? 1 : -1;
2193     }
2194     if (screenLayout != o.screenLayout) {
2195         return (screenLayout > o.screenLayout) ? 1 : -1;
2196     }
2197     if (screenLayout2 != o.screenLayout2) {
2198         return (screenLayout2 > o.screenLayout2) ? 1 : -1;
2199     }
2200     if (colorMode != o.colorMode) {
2201         return (colorMode > o.colorMode) ? 1 : -1;
2202     }
2203     if (uiMode != o.uiMode) {
2204         return (uiMode > o.uiMode) ? 1 : -1;
2205     }
2206     if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
2207         return (smallestScreenWidthDp > o.smallestScreenWidthDp) ? 1 : -1;
2208     }
2209     if (screenSizeDp != o.screenSizeDp) {
2210         return (screenSizeDp > o.screenSizeDp) ? 1 : -1;
2211     }
2212     return 0;
2213 }
2214 
compareLogical(const ResTable_config & o) const2215 int ResTable_config::compareLogical(const ResTable_config& o) const {
2216     if (mcc != o.mcc) {
2217         return mcc < o.mcc ? -1 : 1;
2218     }
2219     if (mnc != o.mnc) {
2220         return mnc < o.mnc ? -1 : 1;
2221     }
2222 
2223     int diff = compareLocales(*this, o);
2224     if (diff < 0) {
2225         return -1;
2226     }
2227     if (diff > 0) {
2228         return 1;
2229     }
2230     if (grammaticalInflection != o.grammaticalInflection) {
2231         return grammaticalInflection < o.grammaticalInflection ? -1 : 1;
2232     }
2233     if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) {
2234         return (screenLayout & MASK_LAYOUTDIR) < (o.screenLayout & MASK_LAYOUTDIR) ? -1 : 1;
2235     }
2236     if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
2237         return smallestScreenWidthDp < o.smallestScreenWidthDp ? -1 : 1;
2238     }
2239     if (screenWidthDp != o.screenWidthDp) {
2240         return screenWidthDp < o.screenWidthDp ? -1 : 1;
2241     }
2242     if (screenHeightDp != o.screenHeightDp) {
2243         return screenHeightDp < o.screenHeightDp ? -1 : 1;
2244     }
2245     if (screenWidth != o.screenWidth) {
2246         return screenWidth < o.screenWidth ? -1 : 1;
2247     }
2248     if (screenHeight != o.screenHeight) {
2249         return screenHeight < o.screenHeight ? -1 : 1;
2250     }
2251     if (density != o.density) {
2252         return density < o.density ? -1 : 1;
2253     }
2254     if (orientation != o.orientation) {
2255         return orientation < o.orientation ? -1 : 1;
2256     }
2257     if (touchscreen != o.touchscreen) {
2258         return touchscreen < o.touchscreen ? -1 : 1;
2259     }
2260     if (input != o.input) {
2261         return input < o.input ? -1 : 1;
2262     }
2263     if (screenLayout != o.screenLayout) {
2264         return screenLayout < o.screenLayout ? -1 : 1;
2265     }
2266     if (screenLayout2 != o.screenLayout2) {
2267         return screenLayout2 < o.screenLayout2 ? -1 : 1;
2268     }
2269     if (colorMode != o.colorMode) {
2270         return colorMode < o.colorMode ? -1 : 1;
2271     }
2272     if (uiMode != o.uiMode) {
2273         return uiMode < o.uiMode ? -1 : 1;
2274     }
2275     if (version != o.version) {
2276         return version < o.version ? -1 : 1;
2277     }
2278     return 0;
2279 }
2280 
diff(const ResTable_config & o) const2281 int ResTable_config::diff(const ResTable_config& o) const {
2282     int diffs = 0;
2283     if (mcc != o.mcc) diffs |= CONFIG_MCC;
2284     if (mnc != o.mnc) diffs |= CONFIG_MNC;
2285     if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
2286     if (density != o.density) diffs |= CONFIG_DENSITY;
2287     if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
2288     if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0)
2289             diffs |= CONFIG_KEYBOARD_HIDDEN;
2290     if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD;
2291     if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
2292     if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
2293     if (version != o.version) diffs |= CONFIG_VERSION;
2294     if ((screenLayout & MASK_LAYOUTDIR) != (o.screenLayout & MASK_LAYOUTDIR)) diffs |= CONFIG_LAYOUTDIR;
2295     if ((screenLayout & ~MASK_LAYOUTDIR) != (o.screenLayout & ~MASK_LAYOUTDIR)) diffs |= CONFIG_SCREEN_LAYOUT;
2296     if ((screenLayout2 & MASK_SCREENROUND) != (o.screenLayout2 & MASK_SCREENROUND)) diffs |= CONFIG_SCREEN_ROUND;
2297     if ((colorMode & MASK_WIDE_COLOR_GAMUT) != (o.colorMode & MASK_WIDE_COLOR_GAMUT)) diffs |= CONFIG_COLOR_MODE;
2298     if ((colorMode & MASK_HDR) != (o.colorMode & MASK_HDR)) diffs |= CONFIG_COLOR_MODE;
2299     if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
2300     if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
2301     if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
2302     if (grammaticalInflection != o.grammaticalInflection) diffs |= CONFIG_GRAMMATICAL_GENDER;
2303 
2304     const int diff = compareLocales(*this, o);
2305     if (diff) diffs |= CONFIG_LOCALE;
2306 
2307     return diffs;
2308 }
2309 
2310 // There isn't a well specified "importance" order between variants and
2311 // scripts. We can't easily tell whether, say "en-Latn-US" is more or less
2312 // specific than "en-US-POSIX".
2313 //
2314 // We therefore arbitrarily decide to give priority to variants over
2315 // scripts since it seems more useful to do so. We will consider
2316 // "en-US-POSIX" to be more specific than "en-Latn-US".
2317 //
2318 // Unicode extension keywords are considered to be less important than
2319 // scripts and variants.
getImportanceScoreOfLocale() const2320 inline int ResTable_config::getImportanceScoreOfLocale() const {
2321   return (localeVariant[0] ? 4 : 0)
2322       + (localeScript[0] && !localeScriptWasComputed ? 2: 0)
2323       + (localeNumberingSystem[0] ? 1: 0);
2324 }
2325 
isLocaleMoreSpecificThan(const ResTable_config & o) const2326 int ResTable_config::isLocaleMoreSpecificThan(const ResTable_config& o) const {
2327     if (locale || o.locale) {
2328         if (language[0] != o.language[0]) {
2329             if (!language[0]) return -1;
2330             if (!o.language[0]) return 1;
2331         }
2332 
2333         if (country[0] != o.country[0]) {
2334             if (!country[0]) return -1;
2335             if (!o.country[0]) return 1;
2336         }
2337     }
2338 
2339     return getImportanceScoreOfLocale() - o.getImportanceScoreOfLocale();
2340 }
2341 
isMoreSpecificThan(const ResTable_config & o) const2342 bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const {
2343     // The order of the following tests defines the importance of one
2344     // configuration parameter over another.  Those tests first are more
2345     // important, trumping any values in those following them.
2346     if (imsi || o.imsi) {
2347         if (mcc != o.mcc) {
2348             if (!mcc) return false;
2349             if (!o.mcc) return true;
2350         }
2351 
2352         if (mnc != o.mnc) {
2353             if (!mnc) return false;
2354             if (!o.mnc) return true;
2355         }
2356     }
2357 
2358     if (locale || o.locale) {
2359         const int diff = isLocaleMoreSpecificThan(o);
2360         if (diff < 0) {
2361             return false;
2362         }
2363 
2364         if (diff > 0) {
2365             return true;
2366         }
2367     }
2368 
2369     if (grammaticalInflection || o.grammaticalInflection) {
2370         if (grammaticalInflection != o.grammaticalInflection) {
2371             if (!grammaticalInflection) return false;
2372             if (!o.grammaticalInflection) return true;
2373         }
2374     }
2375 
2376     if (screenLayout || o.screenLayout) {
2377         if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0) {
2378             if (!(screenLayout & MASK_LAYOUTDIR)) return false;
2379             if (!(o.screenLayout & MASK_LAYOUTDIR)) return true;
2380         }
2381     }
2382 
2383     if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
2384         if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
2385             if (!smallestScreenWidthDp) return false;
2386             if (!o.smallestScreenWidthDp) return true;
2387         }
2388     }
2389 
2390     if (screenSizeDp || o.screenSizeDp) {
2391         if (screenWidthDp != o.screenWidthDp) {
2392             if (!screenWidthDp) return false;
2393             if (!o.screenWidthDp) return true;
2394         }
2395 
2396         if (screenHeightDp != o.screenHeightDp) {
2397             if (!screenHeightDp) return false;
2398             if (!o.screenHeightDp) return true;
2399         }
2400     }
2401 
2402     if (screenLayout || o.screenLayout) {
2403         if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) {
2404             if (!(screenLayout & MASK_SCREENSIZE)) return false;
2405             if (!(o.screenLayout & MASK_SCREENSIZE)) return true;
2406         }
2407         if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) {
2408             if (!(screenLayout & MASK_SCREENLONG)) return false;
2409             if (!(o.screenLayout & MASK_SCREENLONG)) return true;
2410         }
2411     }
2412 
2413     if (screenLayout2 || o.screenLayout2) {
2414         if (((screenLayout2^o.screenLayout2) & MASK_SCREENROUND) != 0) {
2415             if (!(screenLayout2 & MASK_SCREENROUND)) return false;
2416             if (!(o.screenLayout2 & MASK_SCREENROUND)) return true;
2417         }
2418     }
2419 
2420     if (colorMode || o.colorMode) {
2421         if (((colorMode^o.colorMode) & MASK_HDR) != 0) {
2422             if (!(colorMode & MASK_HDR)) return false;
2423             if (!(o.colorMode & MASK_HDR)) return true;
2424         }
2425         if (((colorMode^o.colorMode) & MASK_WIDE_COLOR_GAMUT) != 0) {
2426             if (!(colorMode & MASK_WIDE_COLOR_GAMUT)) return false;
2427             if (!(o.colorMode & MASK_WIDE_COLOR_GAMUT)) return true;
2428         }
2429     }
2430 
2431     if (orientation != o.orientation) {
2432         if (!orientation) return false;
2433         if (!o.orientation) return true;
2434     }
2435 
2436     if (uiMode || o.uiMode) {
2437         if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0) {
2438             if (!(uiMode & MASK_UI_MODE_TYPE)) return false;
2439             if (!(o.uiMode & MASK_UI_MODE_TYPE)) return true;
2440         }
2441         if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0) {
2442             if (!(uiMode & MASK_UI_MODE_NIGHT)) return false;
2443             if (!(o.uiMode & MASK_UI_MODE_NIGHT)) return true;
2444         }
2445     }
2446 
2447     // density is never 'more specific'
2448     // as the default just equals 160
2449 
2450     if (touchscreen != o.touchscreen) {
2451         if (!touchscreen) return false;
2452         if (!o.touchscreen) return true;
2453     }
2454 
2455     if (input || o.input) {
2456         if (((inputFlags^o.inputFlags) & MASK_KEYSHIDDEN) != 0) {
2457             if (!(inputFlags & MASK_KEYSHIDDEN)) return false;
2458             if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true;
2459         }
2460 
2461         if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) {
2462             if (!(inputFlags & MASK_NAVHIDDEN)) return false;
2463             if (!(o.inputFlags & MASK_NAVHIDDEN)) return true;
2464         }
2465 
2466         if (keyboard != o.keyboard) {
2467             if (!keyboard) return false;
2468             if (!o.keyboard) return true;
2469         }
2470 
2471         if (navigation != o.navigation) {
2472             if (!navigation) return false;
2473             if (!o.navigation) return true;
2474         }
2475     }
2476 
2477     if (screenSize || o.screenSize) {
2478         if (screenWidth != o.screenWidth) {
2479             if (!screenWidth) return false;
2480             if (!o.screenWidth) return true;
2481         }
2482 
2483         if (screenHeight != o.screenHeight) {
2484             if (!screenHeight) return false;
2485             if (!o.screenHeight) return true;
2486         }
2487     }
2488 
2489     if (version || o.version) {
2490         if (sdkVersion != o.sdkVersion) {
2491             if (!sdkVersion) return false;
2492             if (!o.sdkVersion) return true;
2493         }
2494 
2495         if (minorVersion != o.minorVersion) {
2496             if (!minorVersion) return false;
2497             if (!o.minorVersion) return true;
2498         }
2499     }
2500     return false;
2501 }
2502 
2503 // Codes for specially handled languages and regions
2504 static const char kEnglish[2] = {'e', 'n'};  // packed version of "en"
2505 static const char kUnitedStates[2] = {'U', 'S'};  // packed version of "US"
2506 static const char kFilipino[2] = {'\xAD', '\x05'};  // packed version of "fil"
2507 static const char kTagalog[2] = {'t', 'l'};  // packed version of "tl"
2508 
2509 // Checks if two language or region codes are identical
areIdentical(const char code1[2],const char code2[2])2510 inline bool areIdentical(const char code1[2], const char code2[2]) {
2511     return code1[0] == code2[0] && code1[1] == code2[1];
2512 }
2513 
langsAreEquivalent(const char lang1[2],const char lang2[2])2514 inline bool langsAreEquivalent(const char lang1[2], const char lang2[2]) {
2515     return areIdentical(lang1, lang2) ||
2516             (areIdentical(lang1, kTagalog) && areIdentical(lang2, kFilipino)) ||
2517             (areIdentical(lang1, kFilipino) && areIdentical(lang2, kTagalog));
2518 }
2519 
isLocaleBetterThan(const ResTable_config & o,const ResTable_config * requested) const2520 bool ResTable_config::isLocaleBetterThan(const ResTable_config& o,
2521         const ResTable_config* requested) const {
2522     if (requested->locale == 0) {
2523         // The request doesn't have a locale, so no resource is better
2524         // than the other.
2525         return false;
2526     }
2527 
2528     if (locale == 0 && o.locale == 0) {
2529         // The locale part of both resources is empty, so none is better
2530         // than the other.
2531         return false;
2532     }
2533 
2534     // Non-matching locales have been filtered out, so both resources
2535     // match the requested locale.
2536     //
2537     // Because of the locale-related checks in match() and the checks, we know
2538     // that:
2539     // 1) The resource languages are either empty or match the request;
2540     // and
2541     // 2) If the request's script is known, the resource scripts are either
2542     //    unknown or match the request.
2543 
2544     if (!langsAreEquivalent(language, o.language)) {
2545         // The languages of the two resources are not equivalent. If we are
2546         // here, we can only assume that the two resources matched the request
2547         // because one doesn't have a language and the other has a matching
2548         // language.
2549         //
2550         // We consider the one that has the language specified a better match.
2551         //
2552         // The exception is that we consider no-language resources a better match
2553         // for US English and similar locales than locales that are a descendant
2554         // of Internatinal English (en-001), since no-language resources are
2555         // where the US English resource have traditionally lived for most apps.
2556         if (areIdentical(requested->language, kEnglish)) {
2557             if (areIdentical(requested->country, kUnitedStates)) {
2558                 // For US English itself, we consider a no-locale resource a
2559                 // better match if the other resource has a country other than
2560                 // US specified.
2561                 if (language[0] != '\0') {
2562                     return country[0] == '\0' || areIdentical(country, kUnitedStates);
2563                 } else {
2564                     return !(o.country[0] == '\0' || areIdentical(o.country, kUnitedStates));
2565                 }
2566             } else if (localeDataIsCloseToUsEnglish(requested->country)) {
2567                 if (language[0] != '\0') {
2568                     return localeDataIsCloseToUsEnglish(country);
2569                 } else {
2570                     return !localeDataIsCloseToUsEnglish(o.country);
2571                 }
2572             }
2573         }
2574         return (language[0] != '\0');
2575     }
2576 
2577     // If we are here, both the resources have an equivalent non-empty language
2578     // to the request.
2579     //
2580     // Because the languages are equivalent, computeScript() always returns a
2581     // non-empty script for languages it knows about, and we have passed the
2582     // script checks in match(), the scripts are either all unknown or are all
2583     // the same. So we can't gain anything by checking the scripts. We need to
2584     // check the region and variant.
2585 
2586     // See if any of the regions is better than the other.
2587     const int region_comparison = localeDataCompareRegions(
2588             country, o.country,
2589             requested->language, requested->localeScript, requested->country);
2590     if (region_comparison != 0) {
2591         return (region_comparison > 0);
2592     }
2593 
2594     // The regions are the same. Try the variant.
2595     const bool localeMatches = strncmp(
2596             localeVariant, requested->localeVariant, sizeof(localeVariant)) == 0;
2597     const bool otherMatches = strncmp(
2598             o.localeVariant, requested->localeVariant, sizeof(localeVariant)) == 0;
2599     if (localeMatches != otherMatches) {
2600         return localeMatches;
2601     }
2602 
2603     // The variants are the same, try numbering system.
2604     const bool localeNumsysMatches = strncmp(localeNumberingSystem,
2605                                              requested->localeNumberingSystem,
2606                                              sizeof(localeNumberingSystem)) == 0;
2607     const bool otherNumsysMatches = strncmp(o.localeNumberingSystem,
2608                                             requested->localeNumberingSystem,
2609                                             sizeof(localeNumberingSystem)) == 0;
2610     if (localeNumsysMatches != otherNumsysMatches) {
2611         return localeNumsysMatches;
2612     }
2613 
2614     // Finally, the languages, although equivalent, may still be different
2615     // (like for Tagalog and Filipino). Identical is better than just
2616     // equivalent.
2617     if (areIdentical(language, requested->language)
2618             && !areIdentical(o.language, requested->language)) {
2619         return true;
2620     }
2621 
2622     return false;
2623 }
2624 
isBetterThanBeforeLocale(const ResTable_config & o,const ResTable_config * requested) const2625 bool ResTable_config::isBetterThanBeforeLocale(const ResTable_config& o,
2626         const ResTable_config* requested) const {
2627     if (requested) {
2628         if (imsi || o.imsi) {
2629             if ((mcc != o.mcc) && requested->mcc) {
2630                 return (mcc);
2631             }
2632 
2633             if ((mnc != o.mnc) && requested->mnc) {
2634                 return (mnc);
2635             }
2636         }
2637     }
2638     return false;
2639 }
2640 
isBetterThan(const ResTable_config & o,const ResTable_config * requested) const2641 bool ResTable_config::isBetterThan(const ResTable_config& o,
2642         const ResTable_config* requested) const {
2643     if (requested) {
2644         if (imsi || o.imsi) {
2645             if ((mcc != o.mcc) && requested->mcc) {
2646                 return (mcc);
2647             }
2648 
2649             if ((mnc != o.mnc) && requested->mnc) {
2650                 return (mnc);
2651             }
2652         }
2653         // Cheaper to check for the empty locales here before calling the function
2654         // as we often can skip it completely.
2655         if (requested->locale && (locale || o.locale) && isLocaleBetterThan(o, requested)) {
2656             return true;
2657         }
2658 
2659         if (grammaticalInflection || o.grammaticalInflection) {
2660             if (grammaticalInflection != o.grammaticalInflection
2661                 && requested->grammaticalInflection) {
2662                 return !!grammaticalInflection;
2663             }
2664         }
2665 
2666         if (screenLayout || o.screenLayout) {
2667             if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0
2668                     && (requested->screenLayout & MASK_LAYOUTDIR)) {
2669                 int myLayoutDir = screenLayout & MASK_LAYOUTDIR;
2670                 int oLayoutDir = o.screenLayout & MASK_LAYOUTDIR;
2671                 return (myLayoutDir > oLayoutDir);
2672             }
2673         }
2674 
2675         if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
2676             // The configuration closest to the actual size is best.
2677             // We assume that larger configs have already been filtered
2678             // out at this point.  That means we just want the largest one.
2679             if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
2680                 return smallestScreenWidthDp > o.smallestScreenWidthDp;
2681             }
2682         }
2683 
2684         if (screenSizeDp || o.screenSizeDp) {
2685             // "Better" is based on the sum of the difference between both
2686             // width and height from the requested dimensions.  We are
2687             // assuming the invalid configs (with smaller dimens) have
2688             // already been filtered.  Note that if a particular dimension
2689             // is unspecified, we will end up with a large value (the
2690             // difference between 0 and the requested dimension), which is
2691             // good since we will prefer a config that has specified a
2692             // dimension value.
2693             int myDelta = 0, otherDelta = 0;
2694             if (requested->screenWidthDp) {
2695                 myDelta += requested->screenWidthDp - screenWidthDp;
2696                 otherDelta += requested->screenWidthDp - o.screenWidthDp;
2697             }
2698             if (requested->screenHeightDp) {
2699                 myDelta += requested->screenHeightDp - screenHeightDp;
2700                 otherDelta += requested->screenHeightDp - o.screenHeightDp;
2701             }
2702             if (kDebugTableSuperNoisy) {
2703                 ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
2704                         screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
2705                         requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
2706             }
2707             if (myDelta != otherDelta) {
2708                 return myDelta < otherDelta;
2709             }
2710         }
2711 
2712         if (screenLayout || o.screenLayout) {
2713             if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0
2714                     && (requested->screenLayout & MASK_SCREENSIZE)) {
2715                 // A little backwards compatibility here: undefined is
2716                 // considered equivalent to normal.  But only if the
2717                 // requested size is at least normal; otherwise, small
2718                 // is better than the default.
2719                 int mySL = (screenLayout & MASK_SCREENSIZE);
2720                 int oSL = (o.screenLayout & MASK_SCREENSIZE);
2721                 int fixedMySL = mySL;
2722                 int fixedOSL = oSL;
2723                 if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) {
2724                     if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL;
2725                     if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL;
2726                 }
2727                 // For screen size, the best match is the one that is
2728                 // closest to the requested screen size, but not over
2729                 // (the not over part is dealt with in match() below).
2730                 if (fixedMySL == fixedOSL) {
2731                     // If the two are the same, but 'this' is actually
2732                     // undefined, then the other is really a better match.
2733                     if (mySL == 0) return false;
2734                     return true;
2735                 }
2736                 if (fixedMySL != fixedOSL) {
2737                     return fixedMySL > fixedOSL;
2738                 }
2739             }
2740             if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0
2741                     && (requested->screenLayout & MASK_SCREENLONG)) {
2742                 return (screenLayout & MASK_SCREENLONG);
2743             }
2744         }
2745 
2746         if (screenLayout2 || o.screenLayout2) {
2747             if (((screenLayout2^o.screenLayout2) & MASK_SCREENROUND) != 0 &&
2748                     (requested->screenLayout2 & MASK_SCREENROUND)) {
2749                 return screenLayout2 & MASK_SCREENROUND;
2750             }
2751         }
2752 
2753         if (colorMode || o.colorMode) {
2754             if (((colorMode^o.colorMode) & MASK_WIDE_COLOR_GAMUT) != 0 &&
2755                     (requested->colorMode & MASK_WIDE_COLOR_GAMUT)) {
2756                 return colorMode & MASK_WIDE_COLOR_GAMUT;
2757             }
2758             if (((colorMode^o.colorMode) & MASK_HDR) != 0 &&
2759                     (requested->colorMode & MASK_HDR)) {
2760                 return colorMode & MASK_HDR;
2761             }
2762         }
2763 
2764         if ((orientation != o.orientation) && requested->orientation) {
2765             return (orientation);
2766         }
2767 
2768         if (uiMode || o.uiMode) {
2769             if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0
2770                     && (requested->uiMode & MASK_UI_MODE_TYPE)) {
2771                 return (uiMode & MASK_UI_MODE_TYPE);
2772             }
2773             if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0
2774                     && (requested->uiMode & MASK_UI_MODE_NIGHT)) {
2775                 return (uiMode & MASK_UI_MODE_NIGHT);
2776             }
2777         }
2778 
2779         if (screenType || o.screenType) {
2780             if (density != o.density) {
2781                 // Use the system default density (DENSITY_MEDIUM, 160dpi) if none specified.
2782                 const int thisDensity = density ? density : int(ResTable_config::DENSITY_MEDIUM);
2783                 const int otherDensity = o.density ? o.density : int(ResTable_config::DENSITY_MEDIUM);
2784 
2785                 // We always prefer DENSITY_ANY over scaling a density bucket.
2786                 if (thisDensity == ResTable_config::DENSITY_ANY) {
2787                     return true;
2788                 } else if (otherDensity == ResTable_config::DENSITY_ANY) {
2789                     return false;
2790                 }
2791 
2792                 int requestedDensity = requested->density;
2793                 if (requested->density == 0 ||
2794                         requested->density == ResTable_config::DENSITY_ANY) {
2795                     requestedDensity = ResTable_config::DENSITY_MEDIUM;
2796                 }
2797 
2798                 // DENSITY_ANY is now dealt with. We should look to
2799                 // pick a density bucket and potentially scale it.
2800                 // Any density is potentially useful
2801                 // because the system will scale it.  Always prefer
2802                 // scaling down.
2803                 int h = thisDensity;
2804                 int l = otherDensity;
2805                 bool bImBigger = true;
2806                 if (l > h) {
2807                     std::swap(l, h);
2808                     bImBigger = false;
2809                 }
2810 
2811                 if (h == requestedDensity) {
2812                     // This handles the case where l == h == requestedDensity.
2813                     // In that case, this and o are equally good so both
2814                     // true and false are valid. This preserves previous
2815                     // behavior.
2816                     return bImBigger;
2817                 } else if (l >= requestedDensity) {
2818                     // requested value lower than both l and h, give l
2819                     return !bImBigger;
2820                 } else {
2821                     // otherwise give h
2822                     return bImBigger;
2823                 }
2824             }
2825 
2826             if ((touchscreen != o.touchscreen) && requested->touchscreen) {
2827                 return (touchscreen);
2828             }
2829         }
2830 
2831         if (input || o.input) {
2832             const int keysHidden = inputFlags & MASK_KEYSHIDDEN;
2833             const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN;
2834             if (keysHidden != oKeysHidden) {
2835                 const int reqKeysHidden =
2836                         requested->inputFlags & MASK_KEYSHIDDEN;
2837                 if (reqKeysHidden) {
2838 
2839                     if (!keysHidden) return false;
2840                     if (!oKeysHidden) return true;
2841                     // For compatibility, we count KEYSHIDDEN_NO as being
2842                     // the same as KEYSHIDDEN_SOFT.  Here we disambiguate
2843                     // these by making an exact match more specific.
2844                     if (reqKeysHidden == keysHidden) return true;
2845                     if (reqKeysHidden == oKeysHidden) return false;
2846                 }
2847             }
2848 
2849             const int navHidden = inputFlags & MASK_NAVHIDDEN;
2850             const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
2851             if (navHidden != oNavHidden) {
2852                 const int reqNavHidden =
2853                         requested->inputFlags & MASK_NAVHIDDEN;
2854                 if (reqNavHidden) {
2855 
2856                     if (!navHidden) return false;
2857                     if (!oNavHidden) return true;
2858                 }
2859             }
2860 
2861             if ((keyboard != o.keyboard) && requested->keyboard) {
2862                 return (keyboard);
2863             }
2864 
2865             if ((navigation != o.navigation) && requested->navigation) {
2866                 return (navigation);
2867             }
2868         }
2869 
2870         if (screenSize || o.screenSize) {
2871             // "Better" is based on the sum of the difference between both
2872             // width and height from the requested dimensions.  We are
2873             // assuming the invalid configs (with smaller sizes) have
2874             // already been filtered.  Note that if a particular dimension
2875             // is unspecified, we will end up with a large value (the
2876             // difference between 0 and the requested dimension), which is
2877             // good since we will prefer a config that has specified a
2878             // size value.
2879             int myDelta = 0, otherDelta = 0;
2880             if (requested->screenWidth) {
2881                 myDelta += requested->screenWidth - screenWidth;
2882                 otherDelta += requested->screenWidth - o.screenWidth;
2883             }
2884             if (requested->screenHeight) {
2885                 myDelta += requested->screenHeight - screenHeight;
2886                 otherDelta += requested->screenHeight - o.screenHeight;
2887             }
2888             if (myDelta != otherDelta) {
2889                 return myDelta < otherDelta;
2890             }
2891         }
2892 
2893         if (version || o.version) {
2894             if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
2895                 return (sdkVersion > o.sdkVersion);
2896             }
2897 
2898             if ((minorVersion != o.minorVersion) &&
2899                     requested->minorVersion) {
2900                 return (minorVersion);
2901             }
2902         }
2903 
2904         return false;
2905     }
2906     return isMoreSpecificThan(o);
2907 }
2908 
match(const ResTable_config & settings) const2909 bool ResTable_config::match(const ResTable_config& settings) const {
2910     if (imsi != 0) {
2911         if (mcc != 0 && mcc != settings.mcc) {
2912             return false;
2913         }
2914         if (mnc != 0 && mnc != settings.mnc) {
2915             return false;
2916         }
2917     }
2918     if (locale != 0) {
2919         // Don't consider country and variants when deciding matches.
2920         // (Theoretically, the variant can also affect the script. For
2921         // example, "ar-alalc97" probably implies the Latin script, but since
2922         // CLDR doesn't support getting likely scripts for that, we'll assume
2923         // the variant doesn't change the script.)
2924         //
2925         // If two configs differ only in their country and variant,
2926         // they can be weeded out in the isMoreSpecificThan test.
2927         if (!langsAreEquivalent(language, settings.language)) {
2928             return false;
2929         }
2930 
2931         // For backward compatibility and supporting private-use locales, we
2932         // fall back to old behavior if we couldn't determine the script for
2933         // either of the desired locale or the provided locale. But if we could determine
2934         // the scripts, they should be the same for the locales to match.
2935         bool countriesMustMatch = false;
2936         char computed_script[4];
2937         const char* script;
2938         if (settings.localeScript[0] == '\0') { // could not determine the request's script
2939             countriesMustMatch = true;
2940         } else {
2941             if (localeScript[0] == '\0' && !localeScriptWasComputed) {
2942                 // script was not provided or computed, so we try to compute it
2943                 localeDataComputeScript(computed_script, language, country);
2944                 if (computed_script[0] == '\0') { // we could not compute the script
2945                     countriesMustMatch = true;
2946                 } else {
2947                     script = computed_script;
2948                 }
2949             } else { // script was provided, so just use it
2950                 script = localeScript;
2951             }
2952         }
2953 
2954         if (countriesMustMatch) {
2955             if (country[0] != '\0' && !areIdentical(country, settings.country)) {
2956                 return false;
2957             }
2958         } else {
2959             if (memcmp(script, settings.localeScript, sizeof(settings.localeScript)) != 0) {
2960                 return false;
2961             }
2962         }
2963     }
2964 
2965     if (grammaticalInflection && grammaticalInflection != settings.grammaticalInflection) {
2966         return false;
2967     }
2968 
2969     if (screenConfig != 0) {
2970         const int layoutDir = screenLayout&MASK_LAYOUTDIR;
2971         const int setLayoutDir = settings.screenLayout&MASK_LAYOUTDIR;
2972         if (layoutDir != 0 && layoutDir != setLayoutDir) {
2973             return false;
2974         }
2975 
2976         const int screenSize = screenLayout&MASK_SCREENSIZE;
2977         const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
2978         // Any screen sizes for larger screens than the setting do not
2979         // match.
2980         if (screenSize != 0 && screenSize > setScreenSize) {
2981             return false;
2982         }
2983 
2984         const int screenLong = screenLayout&MASK_SCREENLONG;
2985         const int setScreenLong = settings.screenLayout&MASK_SCREENLONG;
2986         if (screenLong != 0 && screenLong != setScreenLong) {
2987             return false;
2988         }
2989 
2990         const int uiModeType = uiMode&MASK_UI_MODE_TYPE;
2991         const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE;
2992         if (uiModeType != 0 && uiModeType != setUiModeType) {
2993             return false;
2994         }
2995 
2996         const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT;
2997         const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT;
2998         if (uiModeNight != 0 && uiModeNight != setUiModeNight) {
2999             return false;
3000         }
3001 
3002         if (smallestScreenWidthDp != 0
3003                 && smallestScreenWidthDp > settings.smallestScreenWidthDp) {
3004             return false;
3005         }
3006     }
3007 
3008     if (screenConfig2 != 0) {
3009         const int screenRound = screenLayout2 & MASK_SCREENROUND;
3010         const int setScreenRound = settings.screenLayout2 & MASK_SCREENROUND;
3011         if (screenRound != 0 && screenRound != setScreenRound) {
3012             return false;
3013         }
3014 
3015         const int hdr = colorMode & MASK_HDR;
3016         const int setHdr = settings.colorMode & MASK_HDR;
3017         if (hdr != 0 && hdr != setHdr) {
3018             return false;
3019         }
3020 
3021         const int wideColorGamut = colorMode & MASK_WIDE_COLOR_GAMUT;
3022         const int setWideColorGamut = settings.colorMode & MASK_WIDE_COLOR_GAMUT;
3023         if (wideColorGamut != 0 && wideColorGamut != setWideColorGamut) {
3024             return false;
3025         }
3026     }
3027 
3028     if (screenSizeDp != 0) {
3029         if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
3030             if (kDebugTableSuperNoisy) {
3031                 ALOGI("Filtering out width %d in requested %d", screenWidthDp,
3032                         settings.screenWidthDp);
3033             }
3034             return false;
3035         }
3036         if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
3037             if (kDebugTableSuperNoisy) {
3038                 ALOGI("Filtering out height %d in requested %d", screenHeightDp,
3039                         settings.screenHeightDp);
3040             }
3041             return false;
3042         }
3043     }
3044     if (screenType != 0) {
3045         if (orientation != 0 && orientation != settings.orientation) {
3046             return false;
3047         }
3048         // density always matches - we can scale it.  See isBetterThan
3049         if (touchscreen != 0 && touchscreen != settings.touchscreen) {
3050             return false;
3051         }
3052     }
3053     if (input != 0) {
3054         const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
3055         const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
3056         if (keysHidden != 0 && keysHidden != setKeysHidden) {
3057             // For compatibility, we count a request for KEYSHIDDEN_NO as also
3058             // matching the more recent KEYSHIDDEN_SOFT.  Basically
3059             // KEYSHIDDEN_NO means there is some kind of keyboard available.
3060             if (kDebugTableSuperNoisy) {
3061                 ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
3062             }
3063             if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) {
3064                 if (kDebugTableSuperNoisy) {
3065                     ALOGI("No match!");
3066                 }
3067                 return false;
3068             }
3069         }
3070         const int navHidden = inputFlags&MASK_NAVHIDDEN;
3071         const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
3072         if (navHidden != 0 && navHidden != setNavHidden) {
3073             return false;
3074         }
3075         if (keyboard != 0 && keyboard != settings.keyboard) {
3076             return false;
3077         }
3078         if (navigation != 0 && navigation != settings.navigation) {
3079             return false;
3080         }
3081     }
3082     if (screenSize != 0) {
3083         if (screenWidth != 0 && screenWidth > settings.screenWidth) {
3084             return false;
3085         }
3086         if (screenHeight != 0 && screenHeight > settings.screenHeight) {
3087             return false;
3088         }
3089     }
3090     if (version != 0) {
3091         if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) {
3092             return false;
3093         }
3094         if (minorVersion != 0 && minorVersion != settings.minorVersion) {
3095             return false;
3096         }
3097     }
3098     return true;
3099 }
3100 
appendDirLocale(String8 & out) const3101 void ResTable_config::appendDirLocale(String8& out) const {
3102     if (!language[0]) {
3103         return;
3104     }
3105     const bool scriptWasProvided = localeScript[0] != '\0' && !localeScriptWasComputed;
3106     if (!scriptWasProvided && !localeVariant[0] && !localeNumberingSystem[0]) {
3107         // Legacy format.
3108         if (out.size() > 0) {
3109             out.append("-");
3110         }
3111 
3112         char buf[4];
3113         size_t len = unpackLanguage(buf);
3114         out.append(buf, len);
3115 
3116         if (country[0]) {
3117             out.append("-r");
3118             len = unpackRegion(buf);
3119             out.append(buf, len);
3120         }
3121         return;
3122     }
3123 
3124     // We are writing the modified BCP 47 tag.
3125     // It starts with 'b+' and uses '+' as a separator.
3126 
3127     if (out.size() > 0) {
3128         out.append("-");
3129     }
3130     out.append("b+");
3131 
3132     char buf[4];
3133     size_t len = unpackLanguage(buf);
3134     out.append(buf, len);
3135 
3136     if (scriptWasProvided) {
3137         out.append("+");
3138         out.append(localeScript, sizeof(localeScript));
3139     }
3140 
3141     if (country[0]) {
3142         out.append("+");
3143         len = unpackRegion(buf);
3144         out.append(buf, len);
3145     }
3146 
3147     if (localeVariant[0]) {
3148         out.append("+");
3149         out.append(localeVariant, strnlen(localeVariant, sizeof(localeVariant)));
3150     }
3151 
3152     if (localeNumberingSystem[0]) {
3153         out.append("+u+nu+");
3154         out.append(localeNumberingSystem,
3155                    strnlen(localeNumberingSystem, sizeof(localeNumberingSystem)));
3156     }
3157 }
3158 
getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN],bool canonicalize) const3159 void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN], bool canonicalize) const {
3160     memset(str, 0, RESTABLE_MAX_LOCALE_LEN);
3161 
3162     // This represents the "any" locale value, which has traditionally been
3163     // represented by the empty string.
3164     if (language[0] == '\0' && country[0] == '\0') {
3165         return;
3166     }
3167 
3168     size_t charsWritten = 0;
3169     if (language[0] != '\0') {
3170         if (canonicalize && areIdentical(language, kTagalog)) {
3171             // Replace Tagalog with Filipino if we are canonicalizing
3172             str[0] = 'f'; str[1] = 'i'; str[2] = 'l'; str[3] = '\0';  // 3-letter code for Filipino
3173             charsWritten += 3;
3174         } else {
3175             charsWritten += unpackLanguage(str);
3176         }
3177     }
3178 
3179     if (localeScript[0] != '\0' && !localeScriptWasComputed) {
3180         if (charsWritten > 0) {
3181             str[charsWritten++] = '-';
3182         }
3183         memcpy(str + charsWritten, localeScript, sizeof(localeScript));
3184         charsWritten += sizeof(localeScript);
3185     }
3186 
3187     if (country[0] != '\0') {
3188         if (charsWritten > 0) {
3189             str[charsWritten++] = '-';
3190         }
3191         charsWritten += unpackRegion(str + charsWritten);
3192     }
3193 
3194     if (localeVariant[0] != '\0') {
3195         if (charsWritten > 0) {
3196             str[charsWritten++] = '-';
3197         }
3198         memcpy(str + charsWritten, localeVariant, sizeof(localeVariant));
3199         charsWritten += strnlen(str + charsWritten, sizeof(localeVariant));
3200     }
3201 
3202     // Add Unicode extension only if at least one other locale component is present
3203     if (localeNumberingSystem[0] != '\0' && charsWritten > 0) {
3204         static constexpr char NU_PREFIX[] = "-u-nu-";
3205         static constexpr size_t NU_PREFIX_LEN = sizeof(NU_PREFIX) - 1;
3206         memcpy(str + charsWritten, NU_PREFIX, NU_PREFIX_LEN);
3207         charsWritten += NU_PREFIX_LEN;
3208         memcpy(str + charsWritten, localeNumberingSystem, sizeof(localeNumberingSystem));
3209     }
3210 }
3211 
3212 struct LocaleParserState {
3213     enum State : uint8_t {
3214         BASE, UNICODE_EXTENSION, IGNORE_THE_REST
3215     } parserState;
3216     enum UnicodeState : uint8_t {
3217         /* Initial state after the Unicode singleton is detected. Either a keyword
3218          * or an attribute is expected. */
3219         NO_KEY,
3220         /* Unicode extension key (but not attribute) is expected. Next states:
3221          * NO_KEY, IGNORE_KEY or NUMBERING_SYSTEM. */
3222         EXPECT_KEY,
3223         /* A key is detected, however it is not supported for now. Ignore its
3224          * value. Next states: IGNORE_KEY or NUMBERING_SYSTEM. */
3225         IGNORE_KEY,
3226         /* Numbering system key was detected. Store its value in the configuration
3227          * localeNumberingSystem field. Next state: EXPECT_KEY */
3228         NUMBERING_SYSTEM
3229     } unicodeState;
3230 
LocaleParserStateandroid::LocaleParserState3231     LocaleParserState(): parserState(BASE), unicodeState(NO_KEY) {}
3232 };
3233 
assignLocaleComponent(ResTable_config * config,const char * start,size_t size,LocaleParserState state)3234 /* static */ inline LocaleParserState assignLocaleComponent(ResTable_config* config,
3235         const char* start, size_t size, LocaleParserState state) {
3236 
3237     /* It is assumed that this function is not invoked with state.parserState
3238      * set to IGNORE_THE_REST. The condition is checked by setBcp47Locale
3239      * function. */
3240 
3241     if (state.parserState == LocaleParserState::UNICODE_EXTENSION) {
3242         switch (size) {
3243             case 1:
3244                 /* Other BCP 47 extensions are not supported at the moment */
3245                 state.parserState = LocaleParserState::IGNORE_THE_REST;
3246                 break;
3247             case 2:
3248                 if (state.unicodeState == LocaleParserState::NO_KEY ||
3249                     state.unicodeState == LocaleParserState::EXPECT_KEY) {
3250                     /* Analyze Unicode extension key. Currently only 'nu'
3251                      * (numbering system) is supported.*/
3252                     if ((start[0] == 'n' || start[0] == 'N') &&
3253                         (start[1] == 'u' || start[1] == 'U')) {
3254                         state.unicodeState = LocaleParserState::NUMBERING_SYSTEM;
3255                     } else {
3256                         state.unicodeState = LocaleParserState::IGNORE_KEY;
3257                     }
3258                 } else {
3259                     /* Keys are not allowed in other state allowed, ignore the rest. */
3260                     state.parserState = LocaleParserState::IGNORE_THE_REST;
3261                 }
3262                 break;
3263             case 3:
3264             case 4:
3265             case 5:
3266             case 6:
3267             case 7:
3268             case 8:
3269                 switch (state.unicodeState) {
3270                     case LocaleParserState::NUMBERING_SYSTEM:
3271                         /* Accept only the first occurrence of the numbering system. */
3272                         if (config->localeNumberingSystem[0] == '\0') {
3273                             for (size_t i = 0; i < size; ++i) {
3274                                config->localeNumberingSystem[i] = tolower(start[i]);
3275                             }
3276                             state.unicodeState = LocaleParserState::EXPECT_KEY;
3277                         } else {
3278                             state.parserState = LocaleParserState::IGNORE_THE_REST;
3279                         }
3280                         break;
3281                     case LocaleParserState::IGNORE_KEY:
3282                         /* Unsupported Unicode keyword. Ignore. */
3283                         state.unicodeState = LocaleParserState::EXPECT_KEY;
3284                         break;
3285                     case LocaleParserState::EXPECT_KEY:
3286                         /* A keyword followed by an attribute is not allowed. */
3287                         state.parserState = LocaleParserState::IGNORE_THE_REST;
3288                         break;
3289                     case LocaleParserState::NO_KEY:
3290                         /* Extension attribute. Do nothing. */
3291                         break;
3292                     default:
3293                         break;
3294                 }
3295                 break;
3296             default:
3297                 /* Unexpected field length - ignore the rest and treat as an error */
3298                 state.parserState = LocaleParserState::IGNORE_THE_REST;
3299         }
3300         return state;
3301     }
3302 
3303   switch (size) {
3304        case 0:
3305            state.parserState = LocaleParserState::IGNORE_THE_REST;
3306            break;
3307        case 1:
3308            state.parserState = (start[0] == 'u' || start[0] == 'U')
3309                    ? LocaleParserState::UNICODE_EXTENSION
3310                    : LocaleParserState::IGNORE_THE_REST;
3311            break;
3312        case 2:
3313        case 3:
3314            config->language[0] ? config->packRegion(start) : config->packLanguage(start);
3315            break;
3316        case 4:
3317            if ('0' <= start[0] && start[0] <= '9') {
3318                // this is a variant, so fall through
3319            } else {
3320                config->localeScript[0] = toupper(start[0]);
3321                for (size_t i = 1; i < 4; ++i) {
3322                    config->localeScript[i] = tolower(start[i]);
3323                }
3324                break;
3325            }
3326            FALLTHROUGH_INTENDED;
3327        case 5:
3328        case 6:
3329        case 7:
3330        case 8:
3331            for (size_t i = 0; i < size; ++i) {
3332                config->localeVariant[i] = tolower(start[i]);
3333            }
3334            break;
3335        default:
3336            state.parserState = LocaleParserState::IGNORE_THE_REST;
3337   }
3338 
3339   return state;
3340 }
3341 
setBcp47Locale(const char * in)3342 void ResTable_config::setBcp47Locale(const char* in) {
3343     clearLocale();
3344 
3345     const char* start = in;
3346     LocaleParserState state;
3347     while (const char* separator = strchr(start, '-')) {
3348         const size_t size = separator - start;
3349         state = assignLocaleComponent(this, start, size, state);
3350         if (state.parserState == LocaleParserState::IGNORE_THE_REST) {
3351             fprintf(stderr, "Invalid BCP-47 locale string: %s\n", in);
3352             break;
3353         }
3354         start = (separator + 1);
3355     }
3356 
3357     if (state.parserState != LocaleParserState::IGNORE_THE_REST) {
3358         const size_t size = strlen(start);
3359         assignLocaleComponent(this, start, size, state);
3360     }
3361 
3362     localeScriptWasComputed = (localeScript[0] == '\0');
3363     if (localeScriptWasComputed) {
3364         computeScript();
3365     }
3366 }
3367 
toString() const3368 String8 ResTable_config::toString() const {
3369     String8 res;
3370 
3371     if (mcc != 0) {
3372         if (res.size() > 0) res.append("-");
3373         res.appendFormat("mcc%d", dtohs(mcc));
3374     }
3375     if (mnc != 0) {
3376         if (res.size() > 0) res.append("-");
3377         res.appendFormat("mnc%d", dtohs(mnc));
3378     }
3379 
3380     appendDirLocale(res);
3381 
3382     if ((grammaticalInflection & GRAMMATICAL_INFLECTION_GENDER_MASK) != 0) {
3383         if (res.size() > 0) res.append("-");
3384         switch (grammaticalInflection & GRAMMATICAL_INFLECTION_GENDER_MASK) {
3385             case GRAMMATICAL_GENDER_NEUTER: res.append("neuter"); break;
3386             case GRAMMATICAL_GENDER_FEMININE: res.append("feminine"); break;
3387             case GRAMMATICAL_GENDER_MASCULINE: res.append("masculine"); break;
3388         }
3389     }
3390 
3391     if ((screenLayout&MASK_LAYOUTDIR) != 0) {
3392         if (res.size() > 0) res.append("-");
3393         switch (screenLayout&ResTable_config::MASK_LAYOUTDIR) {
3394             case ResTable_config::LAYOUTDIR_LTR:
3395                 res.append("ldltr");
3396                 break;
3397             case ResTable_config::LAYOUTDIR_RTL:
3398                 res.append("ldrtl");
3399                 break;
3400             default:
3401                 res.appendFormat("layoutDir=%d",
3402                         dtohs(screenLayout&ResTable_config::MASK_LAYOUTDIR));
3403                 break;
3404         }
3405     }
3406     if (smallestScreenWidthDp != 0) {
3407         if (res.size() > 0) res.append("-");
3408         res.appendFormat("sw%ddp", dtohs(smallestScreenWidthDp));
3409     }
3410     if (screenWidthDp != 0) {
3411         if (res.size() > 0) res.append("-");
3412         res.appendFormat("w%ddp", dtohs(screenWidthDp));
3413     }
3414     if (screenHeightDp != 0) {
3415         if (res.size() > 0) res.append("-");
3416         res.appendFormat("h%ddp", dtohs(screenHeightDp));
3417     }
3418     if ((screenLayout&MASK_SCREENSIZE) != SCREENSIZE_ANY) {
3419         if (res.size() > 0) res.append("-");
3420         switch (screenLayout&ResTable_config::MASK_SCREENSIZE) {
3421             case ResTable_config::SCREENSIZE_SMALL:
3422                 res.append("small");
3423                 break;
3424             case ResTable_config::SCREENSIZE_NORMAL:
3425                 res.append("normal");
3426                 break;
3427             case ResTable_config::SCREENSIZE_LARGE:
3428                 res.append("large");
3429                 break;
3430             case ResTable_config::SCREENSIZE_XLARGE:
3431                 res.append("xlarge");
3432                 break;
3433             default:
3434                 res.appendFormat("screenLayoutSize=%d",
3435                         dtohs(screenLayout&ResTable_config::MASK_SCREENSIZE));
3436                 break;
3437         }
3438     }
3439     if ((screenLayout&MASK_SCREENLONG) != 0) {
3440         if (res.size() > 0) res.append("-");
3441         switch (screenLayout&ResTable_config::MASK_SCREENLONG) {
3442             case ResTable_config::SCREENLONG_NO:
3443                 res.append("notlong");
3444                 break;
3445             case ResTable_config::SCREENLONG_YES:
3446                 res.append("long");
3447                 break;
3448             default:
3449                 res.appendFormat("screenLayoutLong=%d",
3450                         dtohs(screenLayout&ResTable_config::MASK_SCREENLONG));
3451                 break;
3452         }
3453     }
3454     if ((screenLayout2&MASK_SCREENROUND) != 0) {
3455         if (res.size() > 0) res.append("-");
3456         switch (screenLayout2&MASK_SCREENROUND) {
3457             case SCREENROUND_NO:
3458                 res.append("notround");
3459                 break;
3460             case SCREENROUND_YES:
3461                 res.append("round");
3462                 break;
3463             default:
3464                 res.appendFormat("screenRound=%d", dtohs(screenLayout2&MASK_SCREENROUND));
3465                 break;
3466         }
3467     }
3468     if ((colorMode&MASK_WIDE_COLOR_GAMUT) != 0) {
3469         if (res.size() > 0) res.append("-");
3470         switch (colorMode&MASK_WIDE_COLOR_GAMUT) {
3471             case ResTable_config::WIDE_COLOR_GAMUT_NO:
3472                 res.append("nowidecg");
3473                 break;
3474             case ResTable_config::WIDE_COLOR_GAMUT_YES:
3475                 res.append("widecg");
3476                 break;
3477             default:
3478                 res.appendFormat("wideColorGamut=%d", dtohs(colorMode&MASK_WIDE_COLOR_GAMUT));
3479                 break;
3480         }
3481     }
3482     if ((colorMode&MASK_HDR) != 0) {
3483         if (res.size() > 0) res.append("-");
3484         switch (colorMode&MASK_HDR) {
3485             case ResTable_config::HDR_NO:
3486                 res.append("lowdr");
3487                 break;
3488             case ResTable_config::HDR_YES:
3489                 res.append("highdr");
3490                 break;
3491             default:
3492                 res.appendFormat("hdr=%d", dtohs(colorMode&MASK_HDR));
3493                 break;
3494         }
3495     }
3496     if (orientation != ORIENTATION_ANY) {
3497         if (res.size() > 0) res.append("-");
3498         switch (orientation) {
3499             case ResTable_config::ORIENTATION_PORT:
3500                 res.append("port");
3501                 break;
3502             case ResTable_config::ORIENTATION_LAND:
3503                 res.append("land");
3504                 break;
3505             case ResTable_config::ORIENTATION_SQUARE:
3506                 res.append("square");
3507                 break;
3508             default:
3509                 res.appendFormat("orientation=%d", dtohs(orientation));
3510                 break;
3511         }
3512     }
3513     if ((uiMode&MASK_UI_MODE_TYPE) != UI_MODE_TYPE_ANY) {
3514         if (res.size() > 0) res.append("-");
3515         switch (uiMode&ResTable_config::MASK_UI_MODE_TYPE) {
3516             case ResTable_config::UI_MODE_TYPE_DESK:
3517                 res.append("desk");
3518                 break;
3519             case ResTable_config::UI_MODE_TYPE_CAR:
3520                 res.append("car");
3521                 break;
3522             case ResTable_config::UI_MODE_TYPE_TELEVISION:
3523                 res.append("television");
3524                 break;
3525             case ResTable_config::UI_MODE_TYPE_APPLIANCE:
3526                 res.append("appliance");
3527                 break;
3528             case ResTable_config::UI_MODE_TYPE_WATCH:
3529                 res.append("watch");
3530                 break;
3531             case ResTable_config::UI_MODE_TYPE_VR_HEADSET:
3532                 res.append("vrheadset");
3533                 break;
3534             default:
3535                 res.appendFormat("uiModeType=%d",
3536                         dtohs(screenLayout&ResTable_config::MASK_UI_MODE_TYPE));
3537                 break;
3538         }
3539     }
3540     if ((uiMode&MASK_UI_MODE_NIGHT) != 0) {
3541         if (res.size() > 0) res.append("-");
3542         switch (uiMode&ResTable_config::MASK_UI_MODE_NIGHT) {
3543             case ResTable_config::UI_MODE_NIGHT_NO:
3544                 res.append("notnight");
3545                 break;
3546             case ResTable_config::UI_MODE_NIGHT_YES:
3547                 res.append("night");
3548                 break;
3549             default:
3550                 res.appendFormat("uiModeNight=%d",
3551                         dtohs(uiMode&MASK_UI_MODE_NIGHT));
3552                 break;
3553         }
3554     }
3555     if (density != DENSITY_DEFAULT) {
3556         if (res.size() > 0) res.append("-");
3557         switch (density) {
3558             case ResTable_config::DENSITY_LOW:
3559                 res.append("ldpi");
3560                 break;
3561             case ResTable_config::DENSITY_MEDIUM:
3562                 res.append("mdpi");
3563                 break;
3564             case ResTable_config::DENSITY_TV:
3565                 res.append("tvdpi");
3566                 break;
3567             case ResTable_config::DENSITY_HIGH:
3568                 res.append("hdpi");
3569                 break;
3570             case ResTable_config::DENSITY_XHIGH:
3571                 res.append("xhdpi");
3572                 break;
3573             case ResTable_config::DENSITY_XXHIGH:
3574                 res.append("xxhdpi");
3575                 break;
3576             case ResTable_config::DENSITY_XXXHIGH:
3577                 res.append("xxxhdpi");
3578                 break;
3579             case ResTable_config::DENSITY_NONE:
3580                 res.append("nodpi");
3581                 break;
3582             case ResTable_config::DENSITY_ANY:
3583                 res.append("anydpi");
3584                 break;
3585             default:
3586                 res.appendFormat("%ddpi", dtohs(density));
3587                 break;
3588         }
3589     }
3590     if (touchscreen != TOUCHSCREEN_ANY) {
3591         if (res.size() > 0) res.append("-");
3592         switch (touchscreen) {
3593             case ResTable_config::TOUCHSCREEN_NOTOUCH:
3594                 res.append("notouch");
3595                 break;
3596             case ResTable_config::TOUCHSCREEN_FINGER:
3597                 res.append("finger");
3598                 break;
3599             case ResTable_config::TOUCHSCREEN_STYLUS:
3600                 res.append("stylus");
3601                 break;
3602             default:
3603                 res.appendFormat("touchscreen=%d", dtohs(touchscreen));
3604                 break;
3605         }
3606     }
3607     if ((inputFlags&MASK_KEYSHIDDEN) != 0) {
3608         if (res.size() > 0) res.append("-");
3609         switch (inputFlags&MASK_KEYSHIDDEN) {
3610             case ResTable_config::KEYSHIDDEN_NO:
3611                 res.append("keysexposed");
3612                 break;
3613             case ResTable_config::KEYSHIDDEN_YES:
3614                 res.append("keyshidden");
3615                 break;
3616             case ResTable_config::KEYSHIDDEN_SOFT:
3617                 res.append("keyssoft");
3618                 break;
3619         }
3620     }
3621     if (keyboard != KEYBOARD_ANY) {
3622         if (res.size() > 0) res.append("-");
3623         switch (keyboard) {
3624             case ResTable_config::KEYBOARD_NOKEYS:
3625                 res.append("nokeys");
3626                 break;
3627             case ResTable_config::KEYBOARD_QWERTY:
3628                 res.append("qwerty");
3629                 break;
3630             case ResTable_config::KEYBOARD_12KEY:
3631                 res.append("12key");
3632                 break;
3633             default:
3634                 res.appendFormat("keyboard=%d", dtohs(keyboard));
3635                 break;
3636         }
3637     }
3638     if ((inputFlags&MASK_NAVHIDDEN) != 0) {
3639         if (res.size() > 0) res.append("-");
3640         switch (inputFlags&MASK_NAVHIDDEN) {
3641             case ResTable_config::NAVHIDDEN_NO:
3642                 res.append("navexposed");
3643                 break;
3644             case ResTable_config::NAVHIDDEN_YES:
3645                 res.append("navhidden");
3646                 break;
3647             default:
3648                 res.appendFormat("inputFlagsNavHidden=%d",
3649                         dtohs(inputFlags&MASK_NAVHIDDEN));
3650                 break;
3651         }
3652     }
3653     if (navigation != NAVIGATION_ANY) {
3654         if (res.size() > 0) res.append("-");
3655         switch (navigation) {
3656             case ResTable_config::NAVIGATION_NONAV:
3657                 res.append("nonav");
3658                 break;
3659             case ResTable_config::NAVIGATION_DPAD:
3660                 res.append("dpad");
3661                 break;
3662             case ResTable_config::NAVIGATION_TRACKBALL:
3663                 res.append("trackball");
3664                 break;
3665             case ResTable_config::NAVIGATION_WHEEL:
3666                 res.append("wheel");
3667                 break;
3668             default:
3669                 res.appendFormat("navigation=%d", dtohs(navigation));
3670                 break;
3671         }
3672     }
3673     if (screenSize != 0) {
3674         if (res.size() > 0) res.append("-");
3675         res.appendFormat("%dx%d", dtohs(screenWidth), dtohs(screenHeight));
3676     }
3677     if (version != 0) {
3678         if (res.size() > 0) res.append("-");
3679         res.appendFormat("v%d", dtohs(sdkVersion));
3680         if (minorVersion != 0) {
3681             res.appendFormat(".%d", dtohs(minorVersion));
3682         }
3683     }
3684 
3685     return res;
3686 }
3687 
3688 // --------------------------------------------------------------------
3689 // --------------------------------------------------------------------
3690 // --------------------------------------------------------------------
3691 
3692 struct ResTable::Header
3693 {
Headerandroid::ResTable::Header3694     explicit Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
3695         resourceIDMap(NULL), resourceIDMapSize(0) { }
3696 
~Headerandroid::ResTable::Header3697     ~Header()
3698     {
3699         free(resourceIDMap);
3700     }
3701 
3702     const ResTable* const           owner;
3703     void*                           ownedData;
3704     const ResTable_header*          header;
3705     size_t                          size;
3706     const uint8_t*                  dataEnd;
3707     size_t                          index;
3708     int32_t                         cookie;
3709 
3710     ResStringPool                   values;
3711     uint32_t*                       resourceIDMap;
3712     size_t                          resourceIDMapSize;
3713 };
3714 
3715 struct ResTable::Entry {
3716     ResTable_config config;
3717     const ResTable_entry* entry;
3718     const ResTable_type* type;
3719     uint32_t specFlags;
3720     const Package* package;
3721 
3722     StringPoolRef typeStr;
3723     StringPoolRef keyStr;
3724 };
3725 
3726 struct ResTable::Type
3727 {
Typeandroid::ResTable::Type3728     Type(const Header* _header, const Package* _package, size_t count)
3729         : header(_header), package(_package), entryCount(count),
3730           typeSpec(NULL), typeSpecFlags(NULL) { }
3731     const Header* const             header;
3732     const Package* const            package;
3733     const size_t                    entryCount;
3734     const ResTable_typeSpec*        typeSpec;
3735     const uint32_t*                 typeSpecFlags;
3736     IdmapEntries                    idmapEntries;
3737     Vector<const ResTable_type*>    configs;
3738 };
3739 
3740 struct ResTable::Package
3741 {
Packageandroid::ResTable::Package3742     Package(ResTable* _owner, const Header* _header, const ResTable_package* _package)
3743         : owner(_owner), header(_header), package(_package), typeIdOffset(0) {
3744         if (dtohs(package->header.headerSize) == sizeof(*package)) {
3745             // The package structure is the same size as the definition.
3746             // This means it contains the typeIdOffset field.
3747             typeIdOffset = package->typeIdOffset;
3748         }
3749     }
3750 
3751     const ResTable* const           owner;
3752     const Header* const             header;
3753     const ResTable_package* const   package;
3754 
3755     ResStringPool                   typeStrings;
3756     ResStringPool                   keyStrings;
3757 
3758     size_t                          typeIdOffset;
3759     bool                            definesOverlayable = false;
3760 };
3761 
3762 // A group of objects describing a particular resource package.
3763 // The first in 'package' is always the root object (from the resource
3764 // table that defined the package); the ones after are skins on top of it.
3765 struct ResTable::PackageGroup
3766 {
PackageGroupandroid::ResTable::PackageGroup3767     PackageGroup(
3768             ResTable* _owner, const String16& _name, uint32_t _id,
3769             bool appAsLib, bool _isSystemAsset, bool _isDynamic)
3770         : owner(_owner)
3771         , name(_name)
3772         , id(_id)
3773         , largestTypeId(0)
3774         , dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
3775         , isSystemAsset(_isSystemAsset)
3776         , isDynamic(_isDynamic)
3777     { }
3778 
~PackageGroupandroid::ResTable::PackageGroup3779     ~PackageGroup() {
3780         clearBagCache();
3781         const size_t numTypes = types.size();
3782         for (size_t i = 0; i < numTypes; i++) {
3783             TypeList& typeList = types.editItemAt(i);
3784             const size_t numInnerTypes = typeList.size();
3785             for (size_t j = 0; j < numInnerTypes; j++) {
3786                 if (typeList[j]->package->owner == owner) {
3787                     delete typeList[j];
3788                 }
3789             }
3790             typeList.clear();
3791         }
3792 
3793         const size_t N = packages.size();
3794         for (size_t i=0; i<N; i++) {
3795             Package* pkg = packages[i];
3796             if (pkg->owner == owner) {
3797                 delete pkg;
3798             }
3799         }
3800     }
3801 
3802     /**
3803      * Clear all cache related data that depends on parameters/configuration.
3804      * This includes the bag caches and filtered types.
3805      */
clearBagCacheandroid::ResTable::PackageGroup3806     void clearBagCache() {
3807         for (size_t i = 0; i < typeCacheEntries.size(); i++) {
3808             if (kDebugTableNoisy) {
3809                 printf("type=%zu\n", i);
3810             }
3811             const TypeList& typeList = types[i];
3812             if (!typeList.isEmpty()) {
3813                 TypeCacheEntry& cacheEntry = typeCacheEntries.editItemAt(i);
3814 
3815                 // Reset the filtered configurations.
3816                 cacheEntry.filteredConfigs.clear();
3817 
3818                 bag_set** typeBags = cacheEntry.cachedBags;
3819                 if (kDebugTableNoisy) {
3820                     printf("typeBags=%p\n", typeBags);
3821                 }
3822 
3823                 if (typeBags) {
3824                     const size_t N = typeList[0]->entryCount;
3825                     if (kDebugTableNoisy) {
3826                         printf("type->entryCount=%zu\n", N);
3827                     }
3828                     for (size_t j = 0; j < N; j++) {
3829                         if (typeBags[j] && typeBags[j] != (bag_set*)0xFFFFFFFF) {
3830                             free(typeBags[j]);
3831                         }
3832                     }
3833                     free(typeBags);
3834                     cacheEntry.cachedBags = NULL;
3835                 }
3836             }
3837         }
3838     }
3839 
findType16android::ResTable::PackageGroup3840     ssize_t findType16(const char16_t* type, size_t len) const {
3841         const size_t N = packages.size();
3842         for (size_t i = 0; i < N; i++) {
3843             const base::expected<size_t, NullOrIOError> index =
3844                 packages[i]->typeStrings.indexOfString(type, len);
3845             if (index.has_value()) {
3846                 return *index + packages[i]->typeIdOffset;
3847             }
3848         }
3849         return -1;
3850     }
3851 
3852     const ResTable* const           owner;
3853     String16 const                  name;
3854     uint32_t const                  id;
3855 
3856     // This is mainly used to keep track of the loaded packages
3857     // and to clean them up properly. Accessing resources happens from
3858     // the 'types' array.
3859     Vector<Package*>                packages;
3860 
3861     ByteBucketArray<TypeList>       types;
3862 
3863     uint8_t                         largestTypeId;
3864 
3865     // Cached objects dependent on the parameters/configuration of this ResTable.
3866     // Gets cleared whenever the parameters/configuration changes.
3867     // These are stored here in a parallel structure because the data in `types` may
3868     // be shared by other ResTable's (framework resources are shared this way).
3869     ByteBucketArray<TypeCacheEntry> typeCacheEntries;
3870 
3871     // The table mapping dynamic references to resolved references for
3872     // this package group.
3873     // TODO: We may be able to support dynamic references in overlays
3874     // by having these tables in a per-package scope rather than
3875     // per-package-group.
3876     DynamicRefTable                 dynamicRefTable;
3877 
3878     // If the package group comes from a system asset. Used in
3879     // determining non-system locales.
3880     const bool                      isSystemAsset;
3881     const bool isDynamic;
3882 };
3883 
Theme(const ResTable & table)3884 ResTable::Theme::Theme(const ResTable& table)
3885     : mTable(table)
3886     , mTypeSpecFlags(0)
3887 {
3888     memset(mPackages, 0, sizeof(mPackages));
3889 }
3890 
~Theme()3891 ResTable::Theme::~Theme()
3892 {
3893     for (size_t i=0; i<Res_MAXPACKAGE; i++) {
3894         package_info* pi = mPackages[i];
3895         if (pi != NULL) {
3896             free_package(pi);
3897         }
3898     }
3899 }
3900 
free_package(package_info * pi)3901 void ResTable::Theme::free_package(package_info* pi)
3902 {
3903     for (size_t j = 0; j <= Res_MAXTYPE; j++) {
3904         theme_entry* te = pi->types[j].entries;
3905         if (te != NULL) {
3906             free(te);
3907         }
3908     }
3909     free(pi);
3910 }
3911 
copy_package(package_info * pi)3912 ResTable::Theme::package_info* ResTable::Theme::copy_package(package_info* pi)
3913 {
3914     package_info* newpi = (package_info*)malloc(sizeof(package_info));
3915     for (size_t j = 0; j <= Res_MAXTYPE; j++) {
3916         size_t cnt = pi->types[j].numEntries;
3917         newpi->types[j].numEntries = cnt;
3918         theme_entry* te = pi->types[j].entries;
3919         size_t cnt_max = SIZE_MAX / sizeof(theme_entry);
3920         if (te != NULL && (cnt < 0xFFFFFFFF-1) && (cnt < cnt_max)) {
3921             theme_entry* newte = (theme_entry*)malloc(cnt*sizeof(theme_entry));
3922             newpi->types[j].entries = newte;
3923             memcpy(newte, te, cnt*sizeof(theme_entry));
3924         } else {
3925             newpi->types[j].entries = NULL;
3926         }
3927     }
3928     return newpi;
3929 }
3930 
applyStyle(uint32_t resID,bool force)3931 status_t ResTable::Theme::applyStyle(uint32_t resID, bool force)
3932 {
3933     const bag_entry* bag;
3934     uint32_t bagTypeSpecFlags = 0;
3935     mTable.lock();
3936     const ssize_t N = mTable.getBagLocked(resID, &bag, &bagTypeSpecFlags);
3937     if (kDebugTableNoisy) {
3938         ALOGV("Applying style 0x%08x to theme %p, count=%zu", resID, this, N);
3939     }
3940     if (N < 0) {
3941         mTable.unlock();
3942         return N;
3943     }
3944 
3945     mTypeSpecFlags |= bagTypeSpecFlags;
3946 
3947     uint32_t curPackage = 0xffffffff;
3948     ssize_t curPackageIndex = 0;
3949     package_info* curPI = NULL;
3950     uint32_t curType = 0xffffffff;
3951     size_t numEntries = 0;
3952     theme_entry* curEntries = NULL;
3953 
3954     const bag_entry* end = bag + N;
3955     while (bag < end) {
3956         const uint32_t attrRes = bag->map.name.ident;
3957         const uint32_t p = Res_GETPACKAGE(attrRes);
3958         const uint32_t t = Res_GETTYPE(attrRes);
3959         const uint32_t e = Res_GETENTRY(attrRes);
3960 
3961         if (curPackage != p) {
3962             const ssize_t pidx = mTable.getResourcePackageIndex(attrRes);
3963             if (pidx < 0) {
3964                 ALOGE("Style contains key with bad package: 0x%08x\n", attrRes);
3965                 bag++;
3966                 continue;
3967             }
3968             curPackage = p;
3969             curPackageIndex = pidx;
3970             curPI = mPackages[pidx];
3971             if (curPI == NULL) {
3972                 curPI = (package_info*)malloc(sizeof(package_info));
3973                 memset(curPI, 0, sizeof(*curPI));
3974                 mPackages[pidx] = curPI;
3975             }
3976             curType = 0xffffffff;
3977         }
3978         if (curType != t) {
3979             if (t > Res_MAXTYPE) {
3980                 ALOGE("Style contains key with bad type: 0x%08x\n", attrRes);
3981                 bag++;
3982                 continue;
3983             }
3984             curType = t;
3985             curEntries = curPI->types[t].entries;
3986             if (curEntries == NULL) {
3987                 PackageGroup* const grp = mTable.mPackageGroups[curPackageIndex];
3988                 const TypeList& typeList = grp->types[t];
3989                 size_t cnt = typeList.isEmpty() ? 0 : typeList[0]->entryCount;
3990                 size_t cnt_max = SIZE_MAX / sizeof(theme_entry);
3991                 size_t buff_size = (cnt < cnt_max && cnt < 0xFFFFFFFF-1) ?
3992                                           cnt*sizeof(theme_entry) : 0;
3993                 curEntries = (theme_entry*)malloc(buff_size);
3994                 memset(curEntries, Res_value::TYPE_NULL, buff_size);
3995                 curPI->types[t].numEntries = cnt;
3996                 curPI->types[t].entries = curEntries;
3997             }
3998             numEntries = curPI->types[t].numEntries;
3999         }
4000         if (e >= numEntries) {
4001             ALOGE("Style contains key with bad entry: 0x%08x\n", attrRes);
4002             bag++;
4003             continue;
4004         }
4005         theme_entry* curEntry = curEntries + e;
4006         if (kDebugTableNoisy) {
4007             ALOGV("Attr 0x%08x: type=0x%x, data=0x%08x; curType=0x%x",
4008                     attrRes, bag->map.value.dataType, bag->map.value.data,
4009                     curEntry->value.dataType);
4010         }
4011         if (force || (curEntry->value.dataType == Res_value::TYPE_NULL
4012                 && curEntry->value.data != Res_value::DATA_NULL_EMPTY)) {
4013             curEntry->stringBlock = bag->stringBlock;
4014             curEntry->typeSpecFlags |= bagTypeSpecFlags;
4015             curEntry->value = bag->map.value;
4016         }
4017 
4018         bag++;
4019     }
4020 
4021     mTable.unlock();
4022 
4023     if (kDebugTableTheme) {
4024         ALOGI("Applying style 0x%08x (force=%d)  theme %p...\n", resID, force, this);
4025         dumpToLog();
4026     }
4027 
4028     return NO_ERROR;
4029 }
4030 
setTo(const Theme & other)4031 status_t ResTable::Theme::setTo(const Theme& other)
4032 {
4033     if (kDebugTableTheme) {
4034         ALOGI("Setting theme %p from theme %p...\n", this, &other);
4035         dumpToLog();
4036         other.dumpToLog();
4037     }
4038 
4039     if (&mTable == &other.mTable) {
4040         for (size_t i=0; i<Res_MAXPACKAGE; i++) {
4041             if (mPackages[i] != NULL) {
4042                 free_package(mPackages[i]);
4043             }
4044             if (other.mPackages[i] != NULL) {
4045                 mPackages[i] = copy_package(other.mPackages[i]);
4046             } else {
4047                 mPackages[i] = NULL;
4048             }
4049         }
4050     } else {
4051         // @todo: need to really implement this, not just copy
4052         // the system package (which is still wrong because it isn't
4053         // fixing up resource references).
4054         for (size_t i=0; i<Res_MAXPACKAGE; i++) {
4055             if (mPackages[i] != NULL) {
4056                 free_package(mPackages[i]);
4057             }
4058             if (i == 0 && other.mPackages[i] != NULL) {
4059                 mPackages[i] = copy_package(other.mPackages[i]);
4060             } else {
4061                 mPackages[i] = NULL;
4062             }
4063         }
4064     }
4065 
4066     mTypeSpecFlags = other.mTypeSpecFlags;
4067 
4068     if (kDebugTableTheme) {
4069         ALOGI("Final theme:");
4070         dumpToLog();
4071     }
4072 
4073     return NO_ERROR;
4074 }
4075 
clear()4076 status_t ResTable::Theme::clear()
4077 {
4078     if (kDebugTableTheme) {
4079         ALOGI("Clearing theme %p...\n", this);
4080         dumpToLog();
4081     }
4082 
4083     for (size_t i = 0; i < Res_MAXPACKAGE; i++) {
4084         if (mPackages[i] != NULL) {
4085             free_package(mPackages[i]);
4086             mPackages[i] = NULL;
4087         }
4088     }
4089 
4090     mTypeSpecFlags = 0;
4091 
4092     if (kDebugTableTheme) {
4093         ALOGI("Final theme:");
4094         dumpToLog();
4095     }
4096 
4097     return NO_ERROR;
4098 }
4099 
getAttribute(uint32_t resID,Res_value * outValue,uint32_t * outTypeSpecFlags) const4100 ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue,
4101         uint32_t* outTypeSpecFlags) const
4102 {
4103     int cnt = 20;
4104 
4105     if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0;
4106 
4107     do {
4108         const ssize_t p = mTable.getResourcePackageIndex(resID);
4109         const uint32_t t = Res_GETTYPE(resID);
4110         const uint32_t e = Res_GETENTRY(resID);
4111 
4112         if (kDebugTableTheme) {
4113             ALOGI("Looking up attr 0x%08x in theme %p", resID, this);
4114         }
4115 
4116         if (p >= 0) {
4117             const package_info* const pi = mPackages[p];
4118             if (kDebugTableTheme) {
4119                 ALOGI("Found package: %p", pi);
4120             }
4121             if (pi != NULL) {
4122                 if (kDebugTableTheme) {
4123                     ALOGI("Desired type index is %u in avail %zu", t, Res_MAXTYPE + 1);
4124                 }
4125                 if (t <= Res_MAXTYPE) {
4126                     const type_info& ti = pi->types[t];
4127                     if (kDebugTableTheme) {
4128                         ALOGI("Desired entry index is %u in avail %zu", e, ti.numEntries);
4129                     }
4130                     if (e < ti.numEntries) {
4131                         const theme_entry& te = ti.entries[e];
4132                         if (outTypeSpecFlags != NULL) {
4133                             *outTypeSpecFlags |= te.typeSpecFlags;
4134                         }
4135                         if (kDebugTableTheme) {
4136                             ALOGI("Theme value: type=0x%x, data=0x%08x",
4137                                     te.value.dataType, te.value.data);
4138                         }
4139                         const uint8_t type = te.value.dataType;
4140                         if (type == Res_value::TYPE_ATTRIBUTE) {
4141                             if (cnt > 0) {
4142                                 cnt--;
4143                                 resID = te.value.data;
4144                                 continue;
4145                             }
4146                             ALOGW("Too many attribute references, stopped at: 0x%08x\n", resID);
4147                             return BAD_INDEX;
4148                         } else if (type != Res_value::TYPE_NULL
4149                                 || te.value.data == Res_value::DATA_NULL_EMPTY) {
4150                             *outValue = te.value;
4151                             return te.stringBlock;
4152                         }
4153                         return BAD_INDEX;
4154                     }
4155                 }
4156             }
4157         }
4158         break;
4159 
4160     } while (true);
4161 
4162     return BAD_INDEX;
4163 }
4164 
resolveAttributeReference(Res_value * inOutValue,ssize_t blockIndex,uint32_t * outLastRef,uint32_t * inoutTypeSpecFlags,ResTable_config * inoutConfig) const4165 ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue,
4166         ssize_t blockIndex, uint32_t* outLastRef,
4167         uint32_t* inoutTypeSpecFlags, ResTable_config* inoutConfig) const
4168 {
4169     //printf("Resolving type=0x%x\n", inOutValue->dataType);
4170     if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) {
4171         uint32_t newTypeSpecFlags;
4172         blockIndex = getAttribute(inOutValue->data, inOutValue, &newTypeSpecFlags);
4173         if (kDebugTableTheme) {
4174             ALOGI("Resolving attr reference: blockIndex=%d, type=0x%x, data=0x%x\n",
4175                     (int)blockIndex, (int)inOutValue->dataType, inOutValue->data);
4176         }
4177         if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newTypeSpecFlags;
4178         //printf("Retrieved attribute new type=0x%x\n", inOutValue->dataType);
4179         if (blockIndex < 0) {
4180             return blockIndex;
4181         }
4182     }
4183     return mTable.resolveReference(inOutValue, blockIndex, outLastRef,
4184             inoutTypeSpecFlags, inoutConfig);
4185 }
4186 
getChangingConfigurations() const4187 uint32_t ResTable::Theme::getChangingConfigurations() const
4188 {
4189     return mTypeSpecFlags;
4190 }
4191 
dumpToLog() const4192 void ResTable::Theme::dumpToLog() const
4193 {
4194     ALOGI("Theme %p:\n", this);
4195     for (size_t i=0; i<Res_MAXPACKAGE; i++) {
4196         package_info* pi = mPackages[i];
4197         if (pi == NULL) continue;
4198 
4199         ALOGI("  Package #0x%02x:\n", (int)(i + 1));
4200         for (size_t j = 0; j <= Res_MAXTYPE; j++) {
4201             type_info& ti = pi->types[j];
4202             if (ti.numEntries == 0) continue;
4203             ALOGI("    Type #0x%02x:\n", (int)(j + 1));
4204             for (size_t k = 0; k < ti.numEntries; k++) {
4205                 const theme_entry& te = ti.entries[k];
4206                 if (te.value.dataType == Res_value::TYPE_NULL) continue;
4207                 ALOGI("      0x%08x: t=0x%x, d=0x%08x (block=%d)\n",
4208                      (int)Res_MAKEID(i, j, k),
4209                      te.value.dataType, (int)te.value.data, (int)te.stringBlock);
4210             }
4211         }
4212     }
4213 }
4214 
ResTable()4215 ResTable::ResTable()
4216     : mError(NO_INIT), mNextPackageId(2)
4217 {
4218     memset(&mParams, 0, sizeof(mParams));
4219     memset(mPackageMap, 0, sizeof(mPackageMap));
4220     if (kDebugTableSuperNoisy) {
4221         ALOGI("Creating ResTable %p\n", this);
4222     }
4223 }
4224 
ResTable(const void * data,size_t size,const int32_t cookie,bool copyData)4225 ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool copyData)
4226     : mError(NO_INIT), mNextPackageId(2)
4227 {
4228     memset(&mParams, 0, sizeof(mParams));
4229     memset(mPackageMap, 0, sizeof(mPackageMap));
4230     addInternal(data, size, NULL, 0, false, cookie, copyData);
4231     LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table");
4232     if (kDebugTableSuperNoisy) {
4233         ALOGI("Creating ResTable %p\n", this);
4234     }
4235 }
4236 
~ResTable()4237 ResTable::~ResTable()
4238 {
4239     if (kDebugTableSuperNoisy) {
4240         ALOGI("Destroying ResTable in %p\n", this);
4241     }
4242     uninit();
4243 }
4244 
getResourcePackageIndex(uint32_t resID) const4245 inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
4246 {
4247     return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
4248 }
4249 
getResourcePackageIndexFromPackage(uint8_t packageID) const4250 inline ssize_t ResTable::getResourcePackageIndexFromPackage(uint8_t packageID) const
4251 {
4252     return ((ssize_t)mPackageMap[packageID])-1;
4253 }
4254 
add(const void * data,size_t size,const int32_t cookie,bool copyData)4255 status_t ResTable::add(const void* data, size_t size, const int32_t cookie, bool copyData) {
4256     return addInternal(data, size, NULL, 0, false, cookie, copyData);
4257 }
4258 
add(const void * data,size_t size,const void * idmapData,size_t idmapDataSize,const int32_t cookie,bool copyData,bool appAsLib)4259 status_t ResTable::add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
4260         const int32_t cookie, bool copyData, bool appAsLib) {
4261     return addInternal(data, size, idmapData, idmapDataSize, appAsLib, cookie, copyData);
4262 }
4263 
add(Asset * asset,const int32_t cookie,bool copyData)4264 status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) {
4265     const void* data = asset->getBuffer(true);
4266     if (data == NULL) {
4267         ALOGW("Unable to get buffer of resource asset file");
4268         return UNKNOWN_ERROR;
4269     }
4270 
4271     return addInternal(data, static_cast<size_t>(asset->getLength()), NULL, false, 0, cookie,
4272             copyData);
4273 }
4274 
add(Asset * asset,Asset * idmapAsset,const int32_t cookie,bool copyData,bool appAsLib,bool isSystemAsset)4275 status_t ResTable::add(
4276         Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
4277         bool appAsLib, bool isSystemAsset) {
4278     const void* data = asset->getBuffer(true);
4279     if (data == NULL) {
4280         ALOGW("Unable to get buffer of resource asset file");
4281         return UNKNOWN_ERROR;
4282     }
4283 
4284     size_t idmapSize = 0;
4285     const void* idmapData = NULL;
4286     if (idmapAsset != NULL) {
4287         idmapData = idmapAsset->getBuffer(true);
4288         if (idmapData == NULL) {
4289             ALOGW("Unable to get buffer of idmap asset file");
4290             return UNKNOWN_ERROR;
4291         }
4292         idmapSize = static_cast<size_t>(idmapAsset->getLength());
4293     }
4294 
4295     return addInternal(data, static_cast<size_t>(asset->getLength()),
4296             idmapData, idmapSize, appAsLib, cookie, copyData, isSystemAsset);
4297 }
4298 
add(ResTable * src,bool isSystemAsset)4299 status_t ResTable::add(ResTable* src, bool isSystemAsset)
4300 {
4301     mError = src->mError;
4302 
4303     for (size_t i=0; i < src->mHeaders.size(); i++) {
4304         mHeaders.add(src->mHeaders[i]);
4305     }
4306 
4307     for (size_t i=0; i < src->mPackageGroups.size(); i++) {
4308         PackageGroup* srcPg = src->mPackageGroups[i];
4309         PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id,
4310                 false /* appAsLib */, isSystemAsset || srcPg->isSystemAsset, srcPg->isDynamic);
4311         for (size_t j=0; j<srcPg->packages.size(); j++) {
4312             pg->packages.add(srcPg->packages[j]);
4313         }
4314 
4315         for (size_t j = 0; j < srcPg->types.size(); j++) {
4316             if (srcPg->types[j].isEmpty()) {
4317                 continue;
4318             }
4319 
4320             TypeList& typeList = pg->types.editItemAt(j);
4321             typeList.appendVector(srcPg->types[j]);
4322         }
4323         pg->dynamicRefTable.addMappings(srcPg->dynamicRefTable);
4324         pg->largestTypeId = max(pg->largestTypeId, srcPg->largestTypeId);
4325         mPackageGroups.add(pg);
4326     }
4327 
4328     memcpy(mPackageMap, src->mPackageMap, sizeof(mPackageMap));
4329 
4330     return mError;
4331 }
4332 
addEmpty(const int32_t cookie)4333 status_t ResTable::addEmpty(const int32_t cookie) {
4334     Header* header = new Header(this);
4335     header->index = mHeaders.size();
4336     header->cookie = cookie;
4337     header->values.setToEmpty();
4338     header->ownedData = calloc(1, sizeof(ResTable_header));
4339 
4340     ResTable_header* resHeader = (ResTable_header*) header->ownedData;
4341     resHeader->header.type = RES_TABLE_TYPE;
4342     resHeader->header.headerSize = sizeof(ResTable_header);
4343     resHeader->header.size = sizeof(ResTable_header);
4344 
4345     header->header = (const ResTable_header*) resHeader;
4346     mHeaders.add(header);
4347     return (mError=NO_ERROR);
4348 }
4349 
addInternal(const void * data,size_t dataSize,const void * idmapData,size_t idmapDataSize,bool appAsLib,const int32_t cookie,bool copyData,bool isSystemAsset)4350 status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
4351         bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset)
4352 {
4353     if (!data) {
4354         return NO_ERROR;
4355     }
4356 
4357     if (dataSize < sizeof(ResTable_header)) {
4358         ALOGE("Invalid data. Size(%d) is smaller than a ResTable_header(%d).",
4359                 (int) dataSize, (int) sizeof(ResTable_header));
4360         return UNKNOWN_ERROR;
4361     }
4362 
4363     Header* header = new Header(this);
4364     header->index = mHeaders.size();
4365     header->cookie = cookie;
4366     if (idmapData != NULL) {
4367         header->resourceIDMap = (uint32_t*) malloc(idmapDataSize);
4368         if (header->resourceIDMap == NULL) {
4369             delete header;
4370             return (mError = NO_MEMORY);
4371         }
4372         memcpy(header->resourceIDMap, idmapData, idmapDataSize);
4373         header->resourceIDMapSize = idmapDataSize;
4374     }
4375     mHeaders.add(header);
4376 
4377     const bool notDeviceEndian = htods(0xf0) != 0xf0;
4378 
4379     if (kDebugLoadTableNoisy) {
4380         ALOGV("Adding resources to ResTable: data=%p, size=%zu, cookie=%d, copy=%d "
4381                 "idmap=%p\n", data, dataSize, cookie, copyData, idmapData);
4382     }
4383 
4384     if (copyData || notDeviceEndian) {
4385         header->ownedData = malloc(dataSize);
4386         if (header->ownedData == NULL) {
4387             return (mError=NO_MEMORY);
4388         }
4389         memcpy(header->ownedData, data, dataSize);
4390         data = header->ownedData;
4391     }
4392 
4393     header->header = (const ResTable_header*)data;
4394     header->size = dtohl(header->header->header.size);
4395     if (kDebugLoadTableSuperNoisy) {
4396         ALOGI("Got size %zu, again size 0x%x, raw size 0x%x\n", header->size,
4397                 dtohl(header->header->header.size), header->header->header.size);
4398     }
4399     if (kDebugLoadTableNoisy) {
4400         ALOGV("Loading ResTable @%p:\n", header->header);
4401     }
4402     if (dtohs(header->header->header.headerSize) > header->size
4403             || header->size > dataSize) {
4404         ALOGW("Bad resource table: header size 0x%x or total size 0x%x is larger than data size 0x%x\n",
4405              (int)dtohs(header->header->header.headerSize),
4406              (int)header->size, (int)dataSize);
4407         return (mError=BAD_TYPE);
4408     }
4409     if (((dtohs(header->header->header.headerSize)|header->size)&0x3) != 0) {
4410         ALOGW("Bad resource table: header size 0x%x or total size 0x%x is not on an integer boundary\n",
4411              (int)dtohs(header->header->header.headerSize),
4412              (int)header->size);
4413         return (mError=BAD_TYPE);
4414     }
4415     header->dataEnd = ((const uint8_t*)header->header) + header->size;
4416 
4417     // Iterate through all chunks.
4418     size_t curPackage = 0;
4419 
4420     const ResChunk_header* chunk =
4421         (const ResChunk_header*)(((const uint8_t*)header->header)
4422                                  + dtohs(header->header->header.headerSize));
4423     while (((const uint8_t*)chunk) <= (header->dataEnd-sizeof(ResChunk_header)) &&
4424            ((const uint8_t*)chunk) <= (header->dataEnd-dtohl(chunk->size))) {
4425         status_t err = validate_chunk(chunk, sizeof(ResChunk_header), header->dataEnd, "ResTable");
4426         if (err != NO_ERROR) {
4427             return (mError=err);
4428         }
4429         if (kDebugTableNoisy) {
4430             ALOGV("Chunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
4431                     dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
4432                     (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
4433         }
4434         const size_t csize = dtohl(chunk->size);
4435         const uint16_t ctype = dtohs(chunk->type);
4436         if (ctype == RES_STRING_POOL_TYPE) {
4437             if (header->values.getError() != NO_ERROR) {
4438                 // Only use the first string chunk; ignore any others that
4439                 // may appear.
4440                 status_t err = header->values.setTo(chunk, csize);
4441                 if (err != NO_ERROR) {
4442                     return (mError=err);
4443                 }
4444             } else {
4445                 ALOGW("Multiple string chunks found in resource table.");
4446             }
4447         } else if (ctype == RES_TABLE_PACKAGE_TYPE) {
4448             if (curPackage >= dtohl(header->header->packageCount)) {
4449                 ALOGW("More package chunks were found than the %d declared in the header.",
4450                      dtohl(header->header->packageCount));
4451                 return (mError=BAD_TYPE);
4452             }
4453 
4454             if (parsePackage(
4455                     (ResTable_package*)chunk, header, appAsLib, isSystemAsset) != NO_ERROR) {
4456                 return mError;
4457             }
4458             curPackage++;
4459         } else {
4460             ALOGW("Unknown chunk type 0x%x in table at %p.\n",
4461                  ctype,
4462                  (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
4463         }
4464         chunk = (const ResChunk_header*)
4465             (((const uint8_t*)chunk) + csize);
4466     }
4467 
4468     if (curPackage < dtohl(header->header->packageCount)) {
4469         ALOGW("Fewer package chunks (%d) were found than the %d declared in the header.",
4470              (int)curPackage, dtohl(header->header->packageCount));
4471         return (mError=BAD_TYPE);
4472     }
4473     mError = header->values.getError();
4474     if (mError != NO_ERROR) {
4475         ALOGW("No string values found in resource table!");
4476     }
4477 
4478     if (kDebugTableNoisy) {
4479         ALOGV("Returning from add with mError=%d\n", mError);
4480     }
4481     return mError;
4482 }
4483 
getError() const4484 status_t ResTable::getError() const
4485 {
4486     return mError;
4487 }
4488 
uninit()4489 void ResTable::uninit()
4490 {
4491     mError = NO_INIT;
4492     size_t N = mPackageGroups.size();
4493     for (size_t i=0; i<N; i++) {
4494         PackageGroup* g = mPackageGroups[i];
4495         delete g;
4496     }
4497     N = mHeaders.size();
4498     for (size_t i=0; i<N; i++) {
4499         Header* header = mHeaders[i];
4500         if (header->owner == this) {
4501             if (header->ownedData) {
4502                 free(header->ownedData);
4503             }
4504             delete header;
4505         }
4506     }
4507 
4508     mPackageGroups.clear();
4509     mHeaders.clear();
4510 }
4511 
getResourceName(uint32_t resID,bool allowUtf8,resource_name * outName) const4512 bool ResTable::getResourceName(uint32_t resID, bool allowUtf8, resource_name* outName) const
4513 {
4514     if (mError != NO_ERROR) {
4515         return false;
4516     }
4517 
4518     const ssize_t p = getResourcePackageIndex(resID);
4519     const int t = Res_GETTYPE(resID);
4520     const int e = Res_GETENTRY(resID);
4521 
4522     if (p < 0) {
4523         if (Res_GETPACKAGE(resID)+1 == 0) {
4524             ALOGW("No package identifier when getting name for resource number 0x%08x", resID);
4525         } else {
4526 #ifndef STATIC_ANDROIDFW_FOR_TOOLS
4527             ALOGW("No known package when getting name for resource number 0x%08x", resID);
4528 #endif
4529         }
4530         return false;
4531     }
4532     if (t < 0) {
4533         ALOGW("No type identifier when getting name for resource number 0x%08x", resID);
4534         return false;
4535     }
4536 
4537     const PackageGroup* const grp = mPackageGroups[p];
4538     if (grp == NULL) {
4539         ALOGW("Bad identifier when getting name for resource number 0x%08x", resID);
4540         return false;
4541     }
4542 
4543     Entry entry;
4544     status_t err = getEntry(grp, t, e, NULL, &entry);
4545     if (err != NO_ERROR) {
4546         return false;
4547     }
4548 
4549     outName->package = grp->name.c_str();
4550     outName->packageLen = grp->name.size();
4551     if (allowUtf8) {
4552         outName->type8 = UnpackOptionalString(entry.typeStr.string8(), &outName->typeLen);
4553         outName->name8 = UnpackOptionalString(entry.keyStr.string8(), &outName->nameLen);
4554     } else {
4555         outName->type8 = NULL;
4556         outName->name8 = NULL;
4557     }
4558     if (outName->type8 == NULL) {
4559         outName->type = UnpackOptionalString(entry.typeStr.string16(), &outName->typeLen);
4560         // If we have a bad index for some reason, we should abort.
4561         if (outName->type == NULL) {
4562             return false;
4563         }
4564     }
4565     if (outName->name8 == NULL) {
4566         outName->name = UnpackOptionalString(entry.keyStr.string16(), &outName->nameLen);
4567         // If we have a bad index for some reason, we should abort.
4568         if (outName->name == NULL) {
4569             return false;
4570         }
4571     }
4572 
4573     return true;
4574 }
4575 
getResource(uint32_t resID,Res_value * outValue,bool mayBeBag,uint16_t density,uint32_t * outSpecFlags,ResTable_config * outConfig) const4576 ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density,
4577         uint32_t* outSpecFlags, ResTable_config* outConfig) const
4578 {
4579     if (mError != NO_ERROR) {
4580         return mError;
4581     }
4582 
4583     const ssize_t p = getResourcePackageIndex(resID);
4584     const int t = Res_GETTYPE(resID);
4585     const int e = Res_GETENTRY(resID);
4586 
4587     if (p < 0) {
4588         if (Res_GETPACKAGE(resID)+1 == 0) {
4589             ALOGW("No package identifier when getting value for resource number 0x%08x", resID);
4590         } else {
4591             ALOGW("No known package when getting value for resource number 0x%08x", resID);
4592         }
4593         return BAD_INDEX;
4594     }
4595     if (t < 0) {
4596         ALOGW("No type identifier when getting value for resource number 0x%08x", resID);
4597         return BAD_INDEX;
4598     }
4599 
4600     const PackageGroup* const grp = mPackageGroups[p];
4601     if (grp == NULL) {
4602         ALOGW("Bad identifier when getting value for resource number 0x%08x", resID);
4603         return BAD_INDEX;
4604     }
4605 
4606     // Allow overriding density
4607     ResTable_config desiredConfig = mParams;
4608     if (density > 0) {
4609         desiredConfig.density = density;
4610     }
4611 
4612     Entry entry;
4613     status_t err = getEntry(grp, t, e, &desiredConfig, &entry);
4614     if (err != NO_ERROR) {
4615         // Only log the failure when we're not running on the host as
4616         // part of a tool. The caller will do its own logging.
4617 #ifndef STATIC_ANDROIDFW_FOR_TOOLS
4618         ALOGW("Failure getting entry for 0x%08x (t=%d e=%d) (error %d)\n",
4619                 resID, t, e, err);
4620 #endif
4621         return err;
4622     }
4623 
4624     if (entry.entry->map_entry()) {
4625         if (!mayBeBag) {
4626             ALOGW("Requesting resource 0x%08x failed because it is complex\n", resID);
4627         }
4628         return BAD_VALUE;
4629     }
4630 
4631     *outValue = entry.entry->value();
4632 
4633     // The reference may be pointing to a resource in a shared library. These
4634     // references have build-time generated package IDs. These ids may not match
4635     // the actual package IDs of the corresponding packages in this ResTable.
4636     // We need to fix the package ID based on a mapping.
4637     if (grp->dynamicRefTable.lookupResourceValue(outValue) != NO_ERROR) {
4638         ALOGW("Failed to resolve referenced package: 0x%08x", outValue->data);
4639         return BAD_VALUE;
4640     }
4641 
4642     if (kDebugTableNoisy) {
4643         size_t len;
4644         printf("Found value: pkg=%zu, type=%d, str=%s, int=%d\n",
4645                 entry.package->header->index,
4646                 outValue->dataType,
4647                 outValue->dataType == Res_value::TYPE_STRING ?
4648                     String8(UnpackOptionalString(
4649                         entry.package->header->values.stringAt(outValue->data), &len)).c_str() :
4650                     "",
4651                 outValue->data);
4652     }
4653 
4654     if (outSpecFlags != NULL) {
4655         *outSpecFlags = entry.specFlags;
4656     }
4657 
4658     if (outConfig != NULL) {
4659         *outConfig = entry.config;
4660     }
4661 
4662     return entry.package->header->index;
4663 }
4664 
resolveReference(Res_value * value,ssize_t blockIndex,uint32_t * outLastRef,uint32_t * inoutTypeSpecFlags,ResTable_config * outConfig) const4665 ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
4666         uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags,
4667         ResTable_config* outConfig) const
4668 {
4669     int count=0;
4670     while (blockIndex >= 0 && value->dataType == Res_value::TYPE_REFERENCE
4671             && value->data != 0 && count < 20) {
4672         if (outLastRef) *outLastRef = value->data;
4673         uint32_t newFlags = 0;
4674         const ssize_t newIndex = getResource(value->data, value, true, 0, &newFlags,
4675                 outConfig);
4676         if (newIndex == BAD_INDEX) {
4677             return BAD_INDEX;
4678         }
4679         if (kDebugTableTheme) {
4680             ALOGI("Resolving reference 0x%x: newIndex=%d, type=0x%x, data=0x%x\n",
4681                     value->data, (int)newIndex, (int)value->dataType, value->data);
4682         }
4683         //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
4684         if (inoutTypeSpecFlags != NULL) *inoutTypeSpecFlags |= newFlags;
4685         if (newIndex < 0) {
4686             // This can fail if the resource being referenced is a style...
4687             // in this case, just return the reference, and expect the
4688             // caller to deal with.
4689             return blockIndex;
4690         }
4691         blockIndex = newIndex;
4692         count++;
4693     }
4694     return blockIndex;
4695 }
4696 
valueToString(const Res_value * value,size_t stringBlock,char16_t[TMP_BUFFER_SIZE],size_t * outLen) const4697 const char16_t* ResTable::valueToString(
4698     const Res_value* value, size_t stringBlock,
4699     char16_t /*tmpBuffer*/ [TMP_BUFFER_SIZE], size_t* outLen) const
4700 {
4701     if (!value) {
4702         return NULL;
4703     }
4704     if (value->dataType == value->TYPE_STRING) {
4705         return UnpackOptionalString(getTableStringBlock(stringBlock)->stringAt(value->data),
4706                                     outLen);
4707     }
4708     // XXX do int to string conversions.
4709     return NULL;
4710 }
4711 
lockBag(uint32_t resID,const bag_entry ** outBag) const4712 ssize_t ResTable::lockBag(uint32_t resID, const bag_entry** outBag) const
4713 {
4714     mLock.lock();
4715     ssize_t err = getBagLocked(resID, outBag);
4716     if (err < NO_ERROR) {
4717         //printf("*** get failed!  unlocking\n");
4718         mLock.unlock();
4719     }
4720     return err;
4721 }
4722 
unlockBag(const bag_entry *) const4723 void ResTable::unlockBag(const bag_entry* /*bag*/) const
4724 {
4725     //printf("<<< unlockBag %p\n", this);
4726     mLock.unlock();
4727 }
4728 
lock() const4729 void ResTable::lock() const
4730 {
4731     mLock.lock();
4732 }
4733 
unlock() const4734 void ResTable::unlock() const
4735 {
4736     mLock.unlock();
4737 }
4738 
getBagLocked(uint32_t resID,const bag_entry ** outBag,uint32_t * outTypeSpecFlags) const4739 ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
4740         uint32_t* outTypeSpecFlags) const
4741 {
4742     if (mError != NO_ERROR) {
4743         return mError;
4744     }
4745 
4746     const ssize_t p = getResourcePackageIndex(resID);
4747     const int t = Res_GETTYPE(resID);
4748     const int e = Res_GETENTRY(resID);
4749 
4750     if (p < 0) {
4751         ALOGW("Invalid package identifier when getting bag for resource number 0x%08x", resID);
4752         return BAD_INDEX;
4753     }
4754     if (t < 0) {
4755         ALOGW("No type identifier when getting bag for resource number 0x%08x", resID);
4756         return BAD_INDEX;
4757     }
4758 
4759     //printf("Get bag: id=0x%08x, p=%d, t=%d\n", resID, p, t);
4760     PackageGroup* const grp = mPackageGroups[p];
4761     if (grp == NULL) {
4762         ALOGW("Bad identifier when getting bag for resource number 0x%08x", resID);
4763         return BAD_INDEX;
4764     }
4765 
4766     const TypeList& typeConfigs = grp->types[t];
4767     if (typeConfigs.isEmpty()) {
4768         ALOGW("Type identifier 0x%x does not exist.", t+1);
4769         return BAD_INDEX;
4770     }
4771 
4772     const size_t NENTRY = typeConfigs[0]->entryCount;
4773     if (e >= (int)NENTRY) {
4774         ALOGW("Entry identifier 0x%x is larger than entry count 0x%x",
4775              e, (int)typeConfigs[0]->entryCount);
4776         return BAD_INDEX;
4777     }
4778 
4779     // First see if we've already computed this bag...
4780     TypeCacheEntry& cacheEntry = grp->typeCacheEntries.editItemAt(t);
4781     bag_set** typeSet = cacheEntry.cachedBags;
4782     if (typeSet) {
4783         bag_set* set = typeSet[e];
4784         if (set) {
4785             if (set != (bag_set*)0xFFFFFFFF) {
4786                 if (outTypeSpecFlags != NULL) {
4787                     *outTypeSpecFlags = set->typeSpecFlags;
4788                 }
4789                 *outBag = (bag_entry*)(set+1);
4790                 if (kDebugTableSuperNoisy) {
4791                     ALOGI("Found existing bag for: 0x%x\n", resID);
4792                 }
4793                 return set->numAttrs;
4794             }
4795             ALOGW("Attempt to retrieve bag 0x%08x which is invalid or in a cycle.",
4796                  resID);
4797             return BAD_INDEX;
4798         }
4799     }
4800 
4801     // Bag not found, we need to compute it!
4802     if (!typeSet) {
4803         typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*));
4804         if (!typeSet) return NO_MEMORY;
4805         cacheEntry.cachedBags = typeSet;
4806     }
4807 
4808     // Mark that we are currently working on this one.
4809     typeSet[e] = (bag_set*)0xFFFFFFFF;
4810 
4811     if (kDebugTableNoisy) {
4812         ALOGI("Building bag: %x\n", resID);
4813     }
4814 
4815     // Now collect all bag attributes
4816     Entry entry;
4817     status_t err = getEntry(grp, t, e, &mParams, &entry);
4818     if (err != NO_ERROR) {
4819         return err;
4820     }
4821 
4822     const uint16_t entrySize = entry.entry->size();
4823     const ResTable_map_entry* map_entry = entry.entry->map_entry();
4824     const uint32_t parent = map_entry ? dtohl(map_entry->parent.ident) : 0;
4825     const uint32_t count = map_entry ? dtohl(map_entry->count) : 0;
4826 
4827     size_t N = count;
4828 
4829     if (kDebugTableNoisy) {
4830         ALOGI("Found map: size=%x parent=%x count=%d\n", entrySize, parent, count);
4831 
4832     // If this map inherits from another, we need to start
4833     // with its parent's values.  Otherwise start out empty.
4834         ALOGI("Creating new bag, entrySize=0x%08x, parent=0x%08x\n", entrySize, parent);
4835     }
4836 
4837     // This is what we are building.
4838     bag_set* set = NULL;
4839 
4840     if (parent) {
4841         uint32_t resolvedParent = parent;
4842 
4843         // Bags encode a parent reference without using the standard
4844         // Res_value structure. That means we must always try to
4845         // resolve a parent reference in case it is actually a
4846         // TYPE_DYNAMIC_REFERENCE.
4847         status_t err = grp->dynamicRefTable.lookupResourceId(&resolvedParent);
4848         if (err != NO_ERROR) {
4849             ALOGE("Failed resolving bag parent id 0x%08x", parent);
4850             return UNKNOWN_ERROR;
4851         }
4852 
4853         const bag_entry* parentBag;
4854         uint32_t parentTypeSpecFlags = 0;
4855         const ssize_t NP = getBagLocked(resolvedParent, &parentBag, &parentTypeSpecFlags);
4856         const size_t NT = ((NP >= 0) ? NP : 0) + N;
4857         set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
4858         if (set == NULL) {
4859             return NO_MEMORY;
4860         }
4861         if (NP > 0) {
4862             memcpy(set+1, parentBag, NP*sizeof(bag_entry));
4863             set->numAttrs = NP;
4864             if (kDebugTableNoisy) {
4865                 ALOGI("Initialized new bag with %zd inherited attributes.\n", NP);
4866             }
4867         } else {
4868             if (kDebugTableNoisy) {
4869                 ALOGI("Initialized new bag with no inherited attributes.\n");
4870             }
4871             set->numAttrs = 0;
4872         }
4873         set->availAttrs = NT;
4874         set->typeSpecFlags = parentTypeSpecFlags;
4875     } else {
4876         set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
4877         if (set == NULL) {
4878             return NO_MEMORY;
4879         }
4880         set->numAttrs = 0;
4881         set->availAttrs = N;
4882         set->typeSpecFlags = 0;
4883     }
4884 
4885     set->typeSpecFlags |= entry.specFlags;
4886 
4887     // Now merge in the new attributes...
4888     size_t curOff = (reinterpret_cast<uintptr_t>(entry.entry) - reinterpret_cast<uintptr_t>(entry.type))
4889         + entrySize;
4890     const ResTable_map* map;
4891     bag_entry* entries = (bag_entry*)(set+1);
4892     size_t curEntry = 0;
4893     uint32_t pos = 0;
4894     if (kDebugTableNoisy) {
4895         ALOGI("Starting with set %p, entries=%p, avail=%zu\n", set, entries, set->availAttrs);
4896     }
4897     while (pos < count) {
4898         if (kDebugTableNoisy) {
4899             ALOGI("Now at %p\n", (void*)curOff);
4900         }
4901 
4902         if (curOff > (dtohl(entry.type->header.size)-sizeof(ResTable_map))) {
4903             ALOGW("ResTable_map at %d is beyond type chunk data %d",
4904                  (int)curOff, dtohl(entry.type->header.size));
4905             free(set);
4906             return BAD_TYPE;
4907         }
4908         map = (const ResTable_map*)(((const uint8_t*)entry.type) + curOff);
4909         N++;
4910 
4911         uint32_t newName = htodl(map->name.ident);
4912         if (!Res_INTERNALID(newName)) {
4913             // Attributes don't have a resource id as the name. They specify
4914             // other data, which would be wrong to change via a lookup.
4915             if (grp->dynamicRefTable.lookupResourceId(&newName) != NO_ERROR) {
4916                 ALOGE("Failed resolving ResTable_map name at %d with ident 0x%08x",
4917                         (int) curOff, (int) newName);
4918                 free(set);
4919                 return UNKNOWN_ERROR;
4920             }
4921         }
4922 
4923         bool isInside;
4924         uint32_t oldName = 0;
4925         while ((isInside=(curEntry < set->numAttrs))
4926                 && (oldName=entries[curEntry].map.name.ident) < newName) {
4927             if (kDebugTableNoisy) {
4928                 ALOGI("#%zu: Keeping existing attribute: 0x%08x\n",
4929                         curEntry, entries[curEntry].map.name.ident);
4930             }
4931             curEntry++;
4932         }
4933 
4934         if ((!isInside) || oldName != newName) {
4935             // This is a new attribute...  figure out what to do with it.
4936             if (set->numAttrs >= set->availAttrs) {
4937                 // Need to alloc more memory...
4938                 const size_t newAvail = set->availAttrs+N;
4939                 void *oldSet = set;
4940                 set = (bag_set*)realloc(set,
4941                                         sizeof(bag_set)
4942                                         + sizeof(bag_entry)*newAvail);
4943                 if (set == NULL) {
4944                     free(oldSet);
4945                     return NO_MEMORY;
4946                 }
4947                 set->availAttrs = newAvail;
4948                 entries = (bag_entry*)(set+1);
4949                 if (kDebugTableNoisy) {
4950                     ALOGI("Reallocated set %p, entries=%p, avail=%zu\n",
4951                             set, entries, set->availAttrs);
4952                 }
4953             }
4954             if (isInside) {
4955                 // Going in the middle, need to make space.
4956                 memmove(entries+curEntry+1, entries+curEntry,
4957                         sizeof(bag_entry)*(set->numAttrs-curEntry));
4958                 set->numAttrs++;
4959             }
4960             if (kDebugTableNoisy) {
4961                 ALOGI("#%zu: Inserting new attribute: 0x%08x\n", curEntry, newName);
4962             }
4963         } else {
4964             if (kDebugTableNoisy) {
4965                 ALOGI("#%zu: Replacing existing attribute: 0x%08x\n", curEntry, oldName);
4966             }
4967         }
4968 
4969         bag_entry* cur = entries+curEntry;
4970 
4971         cur->stringBlock = entry.package->header->index;
4972         cur->map.name.ident = newName;
4973         cur->map.value.copyFrom_dtoh(map->value);
4974         status_t err = grp->dynamicRefTable.lookupResourceValue(&cur->map.value);
4975         if (err != NO_ERROR) {
4976             ALOGE("Reference item(0x%08x) in bag could not be resolved.", cur->map.value.data);
4977             return UNKNOWN_ERROR;
4978         }
4979 
4980         if (kDebugTableNoisy) {
4981             ALOGI("Setting entry #%zu %p: block=%zd, name=0x%08d, type=%d, data=0x%08x\n",
4982                     curEntry, cur, cur->stringBlock, cur->map.name.ident,
4983                     cur->map.value.dataType, cur->map.value.data);
4984         }
4985 
4986         // On to the next!
4987         curEntry++;
4988         pos++;
4989         const size_t size = dtohs(map->value.size);
4990         curOff += size + sizeof(*map)-sizeof(map->value);
4991     }
4992 
4993     if (curEntry > set->numAttrs) {
4994         set->numAttrs = curEntry;
4995     }
4996 
4997     // And this is it...
4998     typeSet[e] = set;
4999     if (set) {
5000         if (outTypeSpecFlags != NULL) {
5001             *outTypeSpecFlags = set->typeSpecFlags;
5002         }
5003         *outBag = (bag_entry*)(set+1);
5004         if (kDebugTableNoisy) {
5005             ALOGI("Returning %zu attrs\n", set->numAttrs);
5006         }
5007         return set->numAttrs;
5008     }
5009     return BAD_INDEX;
5010 }
5011 
setParameters(const ResTable_config * params)5012 void ResTable::setParameters(const ResTable_config* params)
5013 {
5014     AutoMutex _lock(mLock);
5015     AutoMutex _lock2(mFilteredConfigLock);
5016 
5017     if (kDebugTableGetEntry) {
5018         ALOGI("Setting parameters: %s\n", params->toString().c_str());
5019     }
5020     mParams = *params;
5021     for (size_t p = 0; p < mPackageGroups.size(); p++) {
5022         PackageGroup* packageGroup = mPackageGroups.editItemAt(p);
5023         if (kDebugTableNoisy) {
5024             ALOGI("CLEARING BAGS FOR GROUP %zu!", p);
5025         }
5026         packageGroup->clearBagCache();
5027 
5028         // Find which configurations match the set of parameters. This allows for a much
5029         // faster lookup in Lookup() if the set of values is narrowed down.
5030         for (size_t t = 0; t < packageGroup->types.size(); t++) {
5031             if (packageGroup->types[t].isEmpty()) {
5032                 continue;
5033             }
5034 
5035             TypeList& typeList = packageGroup->types.editItemAt(t);
5036 
5037             // Retrieve the cache entry for this type.
5038             TypeCacheEntry& cacheEntry = packageGroup->typeCacheEntries.editItemAt(t);
5039 
5040             for (size_t ts = 0; ts < typeList.size(); ts++) {
5041                 Type* type = typeList.editItemAt(ts);
5042 
5043                 std::shared_ptr<Vector<const ResTable_type*>> newFilteredConfigs =
5044                         std::make_shared<Vector<const ResTable_type*>>();
5045 
5046                 for (size_t ti = 0; ti < type->configs.size(); ti++) {
5047                     ResTable_config config;
5048                     config.copyFromDtoH(type->configs[ti]->config);
5049 
5050                     if (config.match(mParams)) {
5051                         newFilteredConfigs->add(type->configs[ti]);
5052                     }
5053                 }
5054 
5055                 if (kDebugTableNoisy) {
5056                     ALOGD("Updating pkg=%zu type=%zu with %zu filtered configs",
5057                           p, t, newFilteredConfigs->size());
5058                 }
5059 
5060                 cacheEntry.filteredConfigs.add(newFilteredConfigs);
5061             }
5062         }
5063     }
5064 }
5065 
getParameters(ResTable_config * params) const5066 void ResTable::getParameters(ResTable_config* params) const
5067 {
5068     mLock.lock();
5069     *params = mParams;
5070     mLock.unlock();
5071 }
5072 
5073 struct id_name_map {
5074     uint32_t id;
5075     size_t len;
5076     char16_t name[6];
5077 };
5078 
5079 const static id_name_map ID_NAMES[] = {
5080     { ResTable_map::ATTR_TYPE,  5, { '^', 't', 'y', 'p', 'e' } },
5081     { ResTable_map::ATTR_L10N,  5, { '^', 'l', '1', '0', 'n' } },
5082     { ResTable_map::ATTR_MIN,   4, { '^', 'm', 'i', 'n' } },
5083     { ResTable_map::ATTR_MAX,   4, { '^', 'm', 'a', 'x' } },
5084     { ResTable_map::ATTR_OTHER, 6, { '^', 'o', 't', 'h', 'e', 'r' } },
5085     { ResTable_map::ATTR_ZERO,  5, { '^', 'z', 'e', 'r', 'o' } },
5086     { ResTable_map::ATTR_ONE,   4, { '^', 'o', 'n', 'e' } },
5087     { ResTable_map::ATTR_TWO,   4, { '^', 't', 'w', 'o' } },
5088     { ResTable_map::ATTR_FEW,   4, { '^', 'f', 'e', 'w' } },
5089     { ResTable_map::ATTR_MANY,  5, { '^', 'm', 'a', 'n', 'y' } },
5090 };
5091 
identifierForName(const char16_t * name,size_t nameLen,const char16_t * type,size_t typeLen,const char16_t * package,size_t packageLen,uint32_t * outTypeSpecFlags) const5092 uint32_t ResTable::identifierForName(const char16_t* name, size_t nameLen,
5093                                      const char16_t* type, size_t typeLen,
5094                                      const char16_t* package,
5095                                      size_t packageLen,
5096                                      uint32_t* outTypeSpecFlags) const
5097 {
5098     if (kDebugTableSuperNoisy) {
5099         printf("Identifier for name: error=%d\n", mError);
5100     }
5101 
5102     // Check for internal resource identifier as the very first thing, so
5103     // that we will always find them even when there are no resources.
5104     if (name[0] == '^') {
5105         const int N = (sizeof(ID_NAMES)/sizeof(ID_NAMES[0]));
5106         size_t len;
5107         for (int i=0; i<N; i++) {
5108             const id_name_map* m = ID_NAMES + i;
5109             len = m->len;
5110             if (len != nameLen) {
5111                 continue;
5112             }
5113             for (size_t j=1; j<len; j++) {
5114                 if (m->name[j] != name[j]) {
5115                     goto nope;
5116                 }
5117             }
5118             if (outTypeSpecFlags) {
5119                 *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC;
5120             }
5121             return m->id;
5122 nope:
5123             ;
5124         }
5125         if (nameLen > 7) {
5126             if (name[1] == 'i' && name[2] == 'n'
5127                 && name[3] == 'd' && name[4] == 'e' && name[5] == 'x'
5128                 && name[6] == '_') {
5129                 int index = atoi(String8(name + 7, nameLen - 7).c_str());
5130                 if (Res_CHECKID(index)) {
5131                     ALOGW("Array resource index: %d is too large.",
5132                          index);
5133                     return 0;
5134                 }
5135                 if (outTypeSpecFlags) {
5136                     *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC;
5137                 }
5138                 return  Res_MAKEARRAY(index);
5139             }
5140         }
5141         return 0;
5142     }
5143 
5144     if (mError != NO_ERROR) {
5145         return 0;
5146     }
5147 
5148     bool fakePublic = false;
5149 
5150     // Figure out the package and type we are looking in...
5151 
5152     const char16_t* packageEnd = NULL;
5153     const char16_t* typeEnd = NULL;
5154     const char16_t* const nameEnd = name+nameLen;
5155     const char16_t* p = name;
5156     while (p < nameEnd) {
5157         if (*p == ':') packageEnd = p;
5158         else if (*p == '/') typeEnd = p;
5159         p++;
5160     }
5161     if (*name == '@') {
5162         name++;
5163         if (*name == '*') {
5164             fakePublic = true;
5165             name++;
5166         }
5167     }
5168     if (name >= nameEnd) {
5169         return 0;
5170     }
5171 
5172     if (packageEnd) {
5173         package = name;
5174         packageLen = packageEnd-name;
5175         name = packageEnd+1;
5176     } else if (!package) {
5177         return 0;
5178     }
5179 
5180     if (typeEnd) {
5181         type = name;
5182         typeLen = typeEnd-name;
5183         name = typeEnd+1;
5184     } else if (!type) {
5185         return 0;
5186     }
5187 
5188     if (name >= nameEnd) {
5189         return 0;
5190     }
5191     nameLen = nameEnd-name;
5192 
5193     if (kDebugTableNoisy) {
5194         printf("Looking for identifier: type=%s, name=%s, package=%s\n",
5195                 String8(type, typeLen).c_str(),
5196                 String8(name, nameLen).c_str(),
5197                 String8(package, packageLen).c_str());
5198     }
5199 
5200     const String16 attr("attr");
5201     const String16 attrPrivate("^attr-private");
5202 
5203     const size_t NG = mPackageGroups.size();
5204     for (size_t ig=0; ig<NG; ig++) {
5205         const PackageGroup* group = mPackageGroups[ig];
5206 
5207         if (strzcmp16(package, packageLen,
5208                       group->name.c_str(), group->name.size())) {
5209             if (kDebugTableNoisy) {
5210                 printf("Skipping package group: %s\n", String8(group->name).c_str());
5211             }
5212             continue;
5213         }
5214 
5215         const size_t packageCount = group->packages.size();
5216         for (size_t pi = 0; pi < packageCount; pi++) {
5217             const char16_t* targetType = type;
5218             size_t targetTypeLen = typeLen;
5219 
5220             do {
5221                 auto ti = group->packages[pi]->typeStrings.indexOfString(targetType, targetTypeLen);
5222                 if (!ti.has_value()) {
5223                     continue;
5224                 }
5225 
5226                 *ti += group->packages[pi]->typeIdOffset;
5227                 const uint32_t identifier = findEntry(group, *ti, name, nameLen,
5228                         outTypeSpecFlags);
5229                 if (identifier != 0) {
5230                     if (fakePublic && outTypeSpecFlags) {
5231                         *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC;
5232                     }
5233                     return identifier;
5234                 }
5235             } while (strzcmp16(attr.c_str(), attr.size(), targetType, targetTypeLen) == 0
5236                     && (targetType = attrPrivate.c_str())
5237                     && (targetTypeLen = attrPrivate.size())
5238             );
5239         }
5240     }
5241     return 0;
5242 }
5243 
findEntry(const PackageGroup * group,ssize_t typeIndex,const char16_t * name,size_t nameLen,uint32_t * outTypeSpecFlags) const5244 uint32_t ResTable::findEntry(const PackageGroup* group, ssize_t typeIndex, const char16_t* name,
5245         size_t nameLen, uint32_t* outTypeSpecFlags) const {
5246     const TypeList& typeList = group->types[typeIndex];
5247     const size_t typeCount = typeList.size();
5248     for (size_t i = 0; i < typeCount; i++) {
5249         const Type* t = typeList[i];
5250         const base::expected<size_t, NullOrIOError> ei =
5251             t->package->keyStrings.indexOfString(name, nameLen);
5252         if (!ei.has_value()) {
5253             continue;
5254         }
5255 
5256         const size_t configCount = t->configs.size();
5257         for (size_t j = 0; j < configCount; j++) {
5258             const TypeVariant tv(t->configs[j]);
5259             for (TypeVariant::iterator iter = tv.beginEntries();
5260                  iter != tv.endEntries();
5261                  iter++) {
5262                 const ResTable_entry* entry = *iter;
5263                 if (entry == NULL) {
5264                     continue;
5265                 }
5266 
5267                 if (entry->key() == (size_t) *ei) {
5268                     uint32_t resId = Res_MAKEID(group->id - 1, typeIndex, iter.index());
5269                     if (outTypeSpecFlags) {
5270                         Entry result;
5271                         if (getEntry(group, typeIndex, iter.index(), NULL, &result) != NO_ERROR) {
5272                             ALOGW("Failed to find spec flags for 0x%08x", resId);
5273                             return 0;
5274                         }
5275                         *outTypeSpecFlags = result.specFlags;
5276                     }
5277                     return resId;
5278                 }
5279             }
5280         }
5281     }
5282     return 0;
5283 }
5284 
expandResourceRef(const char16_t * refStr,size_t refLen,String16 * outPackage,String16 * outType,String16 * outName,const String16 * defType,const String16 * defPackage,const char ** outErrorMsg,bool * outPublicOnly)5285 bool ResTable::expandResourceRef(const char16_t* refStr, size_t refLen,
5286                                  String16* outPackage,
5287                                  String16* outType,
5288                                  String16* outName,
5289                                  const String16* defType,
5290                                  const String16* defPackage,
5291                                  const char** outErrorMsg,
5292                                  bool* outPublicOnly)
5293 {
5294     const char16_t* packageEnd = NULL;
5295     const char16_t* typeEnd = NULL;
5296     const char16_t* p = refStr;
5297     const char16_t* const end = p + refLen;
5298     while (p < end) {
5299         if (*p == ':') packageEnd = p;
5300         else if (*p == '/') {
5301             typeEnd = p;
5302             break;
5303         }
5304         p++;
5305     }
5306     p = refStr;
5307     if (*p == '@') p++;
5308 
5309     if (outPublicOnly != NULL) {
5310         *outPublicOnly = true;
5311     }
5312     if (*p == '*') {
5313         p++;
5314         if (outPublicOnly != NULL) {
5315             *outPublicOnly = false;
5316         }
5317     }
5318 
5319     if (packageEnd) {
5320         *outPackage = String16(p, packageEnd-p);
5321         p = packageEnd+1;
5322     } else {
5323         if (!defPackage) {
5324             if (outErrorMsg) {
5325                 *outErrorMsg = "No resource package specified";
5326             }
5327             return false;
5328         }
5329         *outPackage = *defPackage;
5330     }
5331     if (typeEnd) {
5332         *outType = String16(p, typeEnd-p);
5333         p = typeEnd+1;
5334     } else {
5335         if (!defType) {
5336             if (outErrorMsg) {
5337                 *outErrorMsg = "No resource type specified";
5338             }
5339             return false;
5340         }
5341         *outType = *defType;
5342     }
5343     *outName = String16(p, end-p);
5344     if(outPackage->empty()) {
5345         if(outErrorMsg) {
5346             *outErrorMsg = "Resource package cannot be an empty string";
5347         }
5348         return false;
5349     }
5350     if(outType->empty()) {
5351         if(outErrorMsg) {
5352             *outErrorMsg = "Resource type cannot be an empty string";
5353         }
5354         return false;
5355     }
5356     if(outName->empty()) {
5357         if(outErrorMsg) {
5358             *outErrorMsg = "Resource id cannot be an empty string";
5359         }
5360         return false;
5361     }
5362     return true;
5363 }
5364 
get_hex(char c,bool * outError)5365 static uint32_t get_hex(char c, bool* outError)
5366 {
5367     if (c >= '0' && c <= '9') {
5368         return c - '0';
5369     } else if (c >= 'a' && c <= 'f') {
5370         return c - 'a' + 0xa;
5371     } else if (c >= 'A' && c <= 'F') {
5372         return c - 'A' + 0xa;
5373     }
5374     *outError = true;
5375     return 0;
5376 }
5377 
5378 struct unit_entry
5379 {
5380     const char* name;
5381     size_t len;
5382     uint8_t type;
5383     uint32_t unit;
5384     float scale;
5385 };
5386 
5387 static const unit_entry unitNames[] = {
5388     { "px", strlen("px"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PX, 1.0f },
5389     { "dip", strlen("dip"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
5390     { "dp", strlen("dp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_DIP, 1.0f },
5391     { "sp", strlen("sp"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_SP, 1.0f },
5392     { "pt", strlen("pt"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_PT, 1.0f },
5393     { "in", strlen("in"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_IN, 1.0f },
5394     { "mm", strlen("mm"), Res_value::TYPE_DIMENSION, Res_value::COMPLEX_UNIT_MM, 1.0f },
5395     { "%", strlen("%"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION, 1.0f/100 },
5396     { "%p", strlen("%p"), Res_value::TYPE_FRACTION, Res_value::COMPLEX_UNIT_FRACTION_PARENT, 1.0f/100 },
5397     { NULL, 0, 0, 0, 0 }
5398 };
5399 
parse_unit(const char * str,Res_value * outValue,float * outScale,const char ** outEnd)5400 static bool parse_unit(const char* str, Res_value* outValue,
5401                        float* outScale, const char** outEnd)
5402 {
5403     const char* end = str;
5404     while (*end != 0 && !isspace((unsigned char)*end)) {
5405         end++;
5406     }
5407     const size_t len = end-str;
5408 
5409     const char* realEnd = end;
5410     while (*realEnd != 0 && isspace((unsigned char)*realEnd)) {
5411         realEnd++;
5412     }
5413     if (*realEnd != 0) {
5414         return false;
5415     }
5416 
5417     const unit_entry* cur = unitNames;
5418     while (cur->name) {
5419         if (len == cur->len && strncmp(cur->name, str, len) == 0) {
5420             outValue->dataType = cur->type;
5421             outValue->data = cur->unit << Res_value::COMPLEX_UNIT_SHIFT;
5422             *outScale = cur->scale;
5423             *outEnd = end;
5424             //printf("Found unit %s for %s\n", cur->name, str);
5425             return true;
5426         }
5427         cur++;
5428     }
5429 
5430     return false;
5431 }
5432 
U16StringToInt(const char16_t * s,size_t len,Res_value * outValue)5433 bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue)
5434 {
5435     while (len > 0 && isspace16(*s)) {
5436         s++;
5437         len--;
5438     }
5439 
5440     if (len <= 0) {
5441         return false;
5442     }
5443 
5444     size_t i = 0;
5445     int64_t val = 0;
5446     bool neg = false;
5447 
5448     if (*s == '-') {
5449         neg = true;
5450         i++;
5451     }
5452 
5453     if (s[i] < '0' || s[i] > '9') {
5454         return false;
5455     }
5456 
5457     static_assert(std::is_same<uint32_t, Res_value::data_type>::value,
5458                   "Res_value::data_type has changed. The range checks in this "
5459                   "function are no longer correct.");
5460 
5461     // Decimal or hex?
5462     bool isHex;
5463     if (len > 1 && s[i] == '0' && s[i+1] == 'x') {
5464         isHex = true;
5465         i += 2;
5466 
5467         if (neg) {
5468             return false;
5469         }
5470 
5471         if (i == len) {
5472             // Just u"0x"
5473             return false;
5474         }
5475 
5476         bool error = false;
5477         while (i < len && !error) {
5478             val = (val*16) + get_hex(s[i], &error);
5479             i++;
5480 
5481             if (val > std::numeric_limits<uint32_t>::max()) {
5482                 return false;
5483             }
5484         }
5485         if (error) {
5486             return false;
5487         }
5488     } else {
5489         isHex = false;
5490         while (i < len) {
5491             if (s[i] < '0' || s[i] > '9') {
5492                 return false;
5493             }
5494             val = (val*10) + s[i]-'0';
5495             i++;
5496 
5497             if ((neg && -val < std::numeric_limits<int32_t>::min()) ||
5498                 (!neg && val > std::numeric_limits<int32_t>::max())) {
5499                 return false;
5500             }
5501         }
5502     }
5503 
5504     if (neg) val = -val;
5505 
5506     while (i < len && isspace16(s[i])) {
5507         i++;
5508     }
5509 
5510     if (i != len) {
5511         return false;
5512     }
5513 
5514     if (outValue) {
5515         outValue->dataType =
5516             isHex ? outValue->TYPE_INT_HEX : outValue->TYPE_INT_DEC;
5517         outValue->data = static_cast<Res_value::data_type>(val);
5518     }
5519     return true;
5520 }
5521 
stringToInt(const char16_t * s,size_t len,Res_value * outValue)5522 bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
5523 {
5524     return U16StringToInt(s, len, outValue);
5525 }
5526 
5527 template <typename T>
parseFloatingPoint(const char16_t * inBuf,size_t inLen,char * tempBuf,const char ** outEnd,T & out)5528 bool parseFloatingPoint(const char16_t* inBuf, size_t inLen, char* tempBuf,
5529                                   const char** outEnd, T& out){
5530     while (inLen > 0 && isspace16(*inBuf)) {
5531         inBuf++;
5532         inLen--;
5533     }
5534 
5535     if (inLen <= 0) {
5536         return false;
5537     }
5538 
5539     int i=0;
5540     while (inLen > 0 && *inBuf != 0 && i < 126) {
5541         if (*inBuf > 255) {
5542             return false;
5543         }
5544         tempBuf[i++] = *inBuf++;
5545         inLen--;
5546     }
5547 
5548     if (inLen > 0) {
5549         return false;
5550     }
5551     if ((tempBuf[0] < '0' || tempBuf[0] > '9') && tempBuf[0] != '.' && tempBuf[0] != '-' && tempBuf[0] != '+') {
5552         return false;
5553     }
5554 
5555     tempBuf[i] = 0;
5556     if constexpr(std::is_same_v<T, float>) {
5557         out = strtof(tempBuf, (char**)outEnd);
5558     } else {
5559         out = strtod(tempBuf, (char**)outEnd);
5560     }
5561     return true;
5562 }
5563 
stringToDouble(const char16_t * s,size_t len,double & d)5564 bool ResTable::stringToDouble(const char16_t* s, size_t len, double& d){
5565     char buf[128];
5566     const char* end = nullptr;
5567     if (!parseFloatingPoint(s, len, buf, &end, d)) {
5568         return false;
5569     }
5570 
5571     while (*end != 0 && isspace((unsigned char)*end)) {
5572         end++;
5573     }
5574 
5575     return *end == 0;
5576 }
5577 
stringToFloat(const char16_t * s,size_t len,Res_value * outValue)5578 bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
5579 {
5580     char buf[128];
5581     const char* end = nullptr;
5582     float f;
5583 
5584     if (!parseFloatingPoint(s, len, buf, &end, f)) {
5585         return false;
5586     }
5587 
5588     if (*end != 0 && !isspace((unsigned char)*end)) {
5589         // Might be a unit...
5590         float scale;
5591         if (parse_unit(end, outValue, &scale, &end)) {
5592             f *= scale;
5593             const bool neg = f < 0;
5594             if (neg) f = -f;
5595             uint64_t bits = (uint64_t)(f*(1<<23)+.5f);
5596             uint32_t radix;
5597             uint32_t shift;
5598             if ((bits&0x7fffff) == 0) {
5599                 // Always use 23p0 if there is no fraction, just to make
5600                 // things easier to read.
5601                 radix = Res_value::COMPLEX_RADIX_23p0;
5602                 shift = 23;
5603             } else if ((bits&0xffffffffff800000LL) == 0) {
5604                 // Magnitude is zero -- can fit in 0 bits of precision.
5605                 radix = Res_value::COMPLEX_RADIX_0p23;
5606                 shift = 0;
5607             } else if ((bits&0xffffffff80000000LL) == 0) {
5608                 // Magnitude can fit in 8 bits of precision.
5609                 radix = Res_value::COMPLEX_RADIX_8p15;
5610                 shift = 8;
5611             } else if ((bits&0xffffff8000000000LL) == 0) {
5612                 // Magnitude can fit in 16 bits of precision.
5613                 radix = Res_value::COMPLEX_RADIX_16p7;
5614                 shift = 16;
5615             } else {
5616                 // Magnitude needs entire range, so no fractional part.
5617                 radix = Res_value::COMPLEX_RADIX_23p0;
5618                 shift = 23;
5619             }
5620             int32_t mantissa = (int32_t)(
5621                 (bits>>shift) & Res_value::COMPLEX_MANTISSA_MASK);
5622             if (neg) {
5623                 mantissa = (-mantissa) & Res_value::COMPLEX_MANTISSA_MASK;
5624             }
5625             outValue->data |=
5626                 (radix<<Res_value::COMPLEX_RADIX_SHIFT)
5627                 | (mantissa<<Res_value::COMPLEX_MANTISSA_SHIFT);
5628             //printf("Input value: %f 0x%016Lx, mult: %f, radix: %d, shift: %d, final: 0x%08x\n",
5629             //       f * (neg ? -1 : 1), bits, f*(1<<23),
5630             //       radix, shift, outValue->data);
5631             return true;
5632         }
5633         return false;
5634     }
5635 
5636     while (*end != 0 && isspace((unsigned char)*end)) {
5637         end++;
5638     }
5639 
5640     if (*end == 0) {
5641         if (outValue) {
5642             outValue->dataType = outValue->TYPE_FLOAT;
5643             *(float*)(&outValue->data) = f;
5644             return true;
5645         }
5646     }
5647 
5648     return false;
5649 }
5650 
stringToValue(Res_value * outValue,String16 * outString,const char16_t * s,size_t len,bool preserveSpaces,bool coerceType,uint32_t attrID,const String16 * defType,const String16 * defPackage,Accessor * accessor,void * accessorCookie,uint32_t attrType,bool enforcePrivate) const5651 bool ResTable::stringToValue(Res_value* outValue, String16* outString,
5652                              const char16_t* s, size_t len,
5653                              bool preserveSpaces, bool coerceType,
5654                              uint32_t attrID,
5655                              const String16* defType,
5656                              const String16* defPackage,
5657                              Accessor* accessor,
5658                              void* accessorCookie,
5659                              uint32_t attrType,
5660                              bool enforcePrivate) const
5661 {
5662     bool localizationSetting = accessor != NULL && accessor->getLocalizationSetting();
5663     const char* errorMsg = NULL;
5664 
5665     outValue->size = sizeof(Res_value);
5666     outValue->res0 = 0;
5667 
5668     // First strip leading/trailing whitespace.  Do this before handling
5669     // escapes, so they can be used to force whitespace into the string.
5670     if (!preserveSpaces) {
5671         while (len > 0 && isspace16(*s)) {
5672             s++;
5673             len--;
5674         }
5675         while (len > 0 && isspace16(s[len-1])) {
5676             len--;
5677         }
5678         // If the string ends with '\', then we keep the space after it.
5679         if (len > 0 && s[len-1] == '\\' && s[len] != 0) {
5680             len++;
5681         }
5682     }
5683 
5684     //printf("Value for: %s\n", String8(s, len).c_str());
5685 
5686     uint32_t l10nReq = ResTable_map::L10N_NOT_REQUIRED;
5687     uint32_t attrMin = 0x80000000, attrMax = 0x7fffffff;
5688     bool fromAccessor = false;
5689     if (attrID != 0 && !Res_INTERNALID(attrID)) {
5690         const ssize_t p = getResourcePackageIndex(attrID);
5691         const bag_entry* bag;
5692         ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
5693         //printf("For attr 0x%08x got bag of %d\n", attrID, cnt);
5694         if (cnt >= 0) {
5695             while (cnt > 0) {
5696                 //printf("Entry 0x%08x = 0x%08x\n", bag->map.name.ident, bag->map.value.data);
5697                 switch (bag->map.name.ident) {
5698                 case ResTable_map::ATTR_TYPE:
5699                     attrType = bag->map.value.data;
5700                     break;
5701                 case ResTable_map::ATTR_MIN:
5702                     attrMin = bag->map.value.data;
5703                     break;
5704                 case ResTable_map::ATTR_MAX:
5705                     attrMax = bag->map.value.data;
5706                     break;
5707                 case ResTable_map::ATTR_L10N:
5708                     l10nReq = bag->map.value.data;
5709                     break;
5710                 }
5711                 bag++;
5712                 cnt--;
5713             }
5714             unlockBag(bag);
5715         } else if (accessor && accessor->getAttributeType(attrID, &attrType)) {
5716             fromAccessor = true;
5717             if (attrType == ResTable_map::TYPE_ENUM
5718                     || attrType == ResTable_map::TYPE_FLAGS
5719                     || attrType == ResTable_map::TYPE_INTEGER) {
5720                 accessor->getAttributeMin(attrID, &attrMin);
5721                 accessor->getAttributeMax(attrID, &attrMax);
5722             }
5723             if (localizationSetting) {
5724                 l10nReq = accessor->getAttributeL10N(attrID);
5725             }
5726         }
5727     }
5728 
5729     const bool canStringCoerce =
5730         coerceType && (attrType&ResTable_map::TYPE_STRING) != 0;
5731 
5732     if (*s == '@') {
5733         outValue->dataType = outValue->TYPE_REFERENCE;
5734 
5735         // Note: we don't check attrType here because the reference can
5736         // be to any other type; we just need to count on the client making
5737         // sure the referenced type is correct.
5738 
5739         //printf("Looking up ref: %s\n", String8(s, len).c_str());
5740 
5741         // It's a reference!
5742         if (len == 5 && s[1]=='n' && s[2]=='u' && s[3]=='l' && s[4]=='l') {
5743             // Special case @null as undefined. This will be converted by
5744             // AssetManager to TYPE_NULL with data DATA_NULL_UNDEFINED.
5745             outValue->data = 0;
5746             return true;
5747         } else if (len == 6 && s[1]=='e' && s[2]=='m' && s[3]=='p' && s[4]=='t' && s[5]=='y') {
5748             // Special case @empty as explicitly defined empty value.
5749             outValue->dataType = Res_value::TYPE_NULL;
5750             outValue->data = Res_value::DATA_NULL_EMPTY;
5751             return true;
5752         } else {
5753             bool createIfNotFound = false;
5754             const char16_t* resourceRefName;
5755             int resourceNameLen;
5756             if (len > 2 && s[1] == '+') {
5757                 createIfNotFound = true;
5758                 resourceRefName = s + 2;
5759                 resourceNameLen = len - 2;
5760             } else if (len > 2 && s[1] == '*') {
5761                 enforcePrivate = false;
5762                 resourceRefName = s + 2;
5763                 resourceNameLen = len - 2;
5764             } else {
5765                 createIfNotFound = false;
5766                 resourceRefName = s + 1;
5767                 resourceNameLen = len - 1;
5768             }
5769             String16 package, type, name;
5770             if (!expandResourceRef(resourceRefName,resourceNameLen, &package, &type, &name,
5771                                    defType, defPackage, &errorMsg)) {
5772                 if (accessor != NULL) {
5773                     accessor->reportError(accessorCookie, errorMsg);
5774                 }
5775                 return false;
5776             }
5777 
5778             uint32_t specFlags = 0;
5779             uint32_t rid = identifierForName(name.c_str(), name.size(), type.c_str(),
5780                     type.size(), package.c_str(), package.size(), &specFlags);
5781             if (rid != 0) {
5782                 if (enforcePrivate) {
5783                     if (accessor == NULL || accessor->getAssetsPackage() != package) {
5784                         if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
5785                             if (accessor != NULL) {
5786                                 accessor->reportError(accessorCookie, "Resource is not public.");
5787                             }
5788                             return false;
5789                         }
5790                     }
5791                 }
5792 
5793                 if (accessor) {
5794                     rid = Res_MAKEID(
5795                         accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
5796                         Res_GETTYPE(rid), Res_GETENTRY(rid));
5797                     if (kDebugTableNoisy) {
5798                         ALOGI("Incl %s:%s/%s: 0x%08x\n",
5799                                 String8(package).c_str(), String8(type).c_str(),
5800                                 String8(name).c_str(), rid);
5801                     }
5802                 }
5803 
5804                 uint32_t packageId = Res_GETPACKAGE(rid) + 1;
5805                 if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) {
5806                     outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
5807                 }
5808                 outValue->data = rid;
5809                 return true;
5810             }
5811 
5812             if (accessor) {
5813                 uint32_t rid = accessor->getCustomResourceWithCreation(package, type, name,
5814                                                                        createIfNotFound);
5815                 if (rid != 0) {
5816                     if (kDebugTableNoisy) {
5817                         ALOGI("Pckg %s:%s/%s: 0x%08x\n",
5818                                 String8(package).c_str(), String8(type).c_str(),
5819                                 String8(name).c_str(), rid);
5820                     }
5821                     uint32_t packageId = Res_GETPACKAGE(rid) + 1;
5822                     if (packageId == 0x00) {
5823                         outValue->data = rid;
5824                         outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
5825                         return true;
5826                     } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {
5827                         // We accept packageId's generated as 0x01 in order to support
5828                         // building the android system resources
5829                         outValue->data = rid;
5830                         return true;
5831                     }
5832                 }
5833             }
5834         }
5835 
5836         if (accessor != NULL) {
5837             accessor->reportError(accessorCookie, "No resource found that matches the given name");
5838         }
5839         return false;
5840     }
5841 
5842     // if we got to here, and localization is required and it's not a reference,
5843     // complain and bail.
5844     if (l10nReq == ResTable_map::L10N_SUGGESTED) {
5845         if (localizationSetting) {
5846             if (accessor != NULL) {
5847                 accessor->reportError(accessorCookie, "This attribute must be localized.");
5848             }
5849         }
5850     }
5851 
5852     if (*s == '#') {
5853         // It's a color!  Convert to an integer of the form 0xaarrggbb.
5854         uint32_t color = 0;
5855         bool error = false;
5856         if (len == 4) {
5857             outValue->dataType = outValue->TYPE_INT_COLOR_RGB4;
5858             color |= 0xFF000000;
5859             color |= get_hex(s[1], &error) << 20;
5860             color |= get_hex(s[1], &error) << 16;
5861             color |= get_hex(s[2], &error) << 12;
5862             color |= get_hex(s[2], &error) << 8;
5863             color |= get_hex(s[3], &error) << 4;
5864             color |= get_hex(s[3], &error);
5865         } else if (len == 5) {
5866             outValue->dataType = outValue->TYPE_INT_COLOR_ARGB4;
5867             color |= get_hex(s[1], &error) << 28;
5868             color |= get_hex(s[1], &error) << 24;
5869             color |= get_hex(s[2], &error) << 20;
5870             color |= get_hex(s[2], &error) << 16;
5871             color |= get_hex(s[3], &error) << 12;
5872             color |= get_hex(s[3], &error) << 8;
5873             color |= get_hex(s[4], &error) << 4;
5874             color |= get_hex(s[4], &error);
5875         } else if (len == 7) {
5876             outValue->dataType = outValue->TYPE_INT_COLOR_RGB8;
5877             color |= 0xFF000000;
5878             color |= get_hex(s[1], &error) << 20;
5879             color |= get_hex(s[2], &error) << 16;
5880             color |= get_hex(s[3], &error) << 12;
5881             color |= get_hex(s[4], &error) << 8;
5882             color |= get_hex(s[5], &error) << 4;
5883             color |= get_hex(s[6], &error);
5884         } else if (len == 9) {
5885             outValue->dataType = outValue->TYPE_INT_COLOR_ARGB8;
5886             color |= get_hex(s[1], &error) << 28;
5887             color |= get_hex(s[2], &error) << 24;
5888             color |= get_hex(s[3], &error) << 20;
5889             color |= get_hex(s[4], &error) << 16;
5890             color |= get_hex(s[5], &error) << 12;
5891             color |= get_hex(s[6], &error) << 8;
5892             color |= get_hex(s[7], &error) << 4;
5893             color |= get_hex(s[8], &error);
5894         } else {
5895             error = true;
5896         }
5897         if (!error) {
5898             if ((attrType&ResTable_map::TYPE_COLOR) == 0) {
5899                 if (!canStringCoerce) {
5900                     if (accessor != NULL) {
5901                         accessor->reportError(accessorCookie,
5902                                 "Color types not allowed");
5903                     }
5904                     return false;
5905                 }
5906             } else {
5907                 outValue->data = color;
5908                 //printf("Color input=%s, output=0x%x\n", String8(s, len).c_str(), color);
5909                 return true;
5910             }
5911         } else {
5912             if ((attrType&ResTable_map::TYPE_COLOR) != 0) {
5913                 if (accessor != NULL) {
5914                     accessor->reportError(accessorCookie, "Color value not valid --"
5915                             " must be #rgb, #argb, #rrggbb, or #aarrggbb");
5916                 }
5917                 #if 0
5918                 fprintf(stderr, "%s: Color ID %s value %s is not valid\n",
5919                         "Resource File", //(const char*)in->getPrintableSource(),
5920                         String8(*curTag).c_str(),
5921                         String8(s, len).c_str());
5922                 #endif
5923                 return false;
5924             }
5925         }
5926     }
5927 
5928     if (*s == '?') {
5929         outValue->dataType = outValue->TYPE_ATTRIBUTE;
5930 
5931         // Note: we don't check attrType here because the reference can
5932         // be to any other type; we just need to count on the client making
5933         // sure the referenced type is correct.
5934 
5935         //printf("Looking up attr: %s\n", String8(s, len).c_str());
5936 
5937         static const String16 attr16("attr");
5938         String16 package, type, name;
5939         if (!expandResourceRef(s+1, len-1, &package, &type, &name,
5940                                &attr16, defPackage, &errorMsg)) {
5941             if (accessor != NULL) {
5942                 accessor->reportError(accessorCookie, errorMsg);
5943             }
5944             return false;
5945         }
5946 
5947         //printf("Pkg: %s, Type: %s, Name: %s\n",
5948         //       String8(package).c_str(), String8(type).c_str(),
5949         //       String8(name).c_str());
5950         uint32_t specFlags = 0;
5951         uint32_t rid =
5952             identifierForName(name.c_str(), name.size(),
5953                               type.c_str(), type.size(),
5954                               package.c_str(), package.size(), &specFlags);
5955         if (rid != 0) {
5956             if (enforcePrivate) {
5957                 if ((specFlags&ResTable_typeSpec::SPEC_PUBLIC) == 0) {
5958                     if (accessor != NULL) {
5959                         accessor->reportError(accessorCookie, "Attribute is not public.");
5960                     }
5961                     return false;
5962                 }
5963             }
5964 
5965             if (accessor) {
5966                 rid = Res_MAKEID(
5967                     accessor->getRemappedPackage(Res_GETPACKAGE(rid)),
5968                     Res_GETTYPE(rid), Res_GETENTRY(rid));
5969             }
5970 
5971             uint32_t packageId = Res_GETPACKAGE(rid) + 1;
5972             if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) {
5973                 outValue->dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE;
5974             }
5975             outValue->data = rid;
5976             return true;
5977         }
5978 
5979         if (accessor) {
5980             uint32_t rid = accessor->getCustomResource(package, type, name);
5981             if (rid != 0) {
5982                 uint32_t packageId = Res_GETPACKAGE(rid) + 1;
5983                 if (packageId == 0x00) {
5984                     outValue->data = rid;
5985                     outValue->dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE;
5986                     return true;
5987                 } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {
5988                     // We accept packageId's generated as 0x01 in order to support
5989                     // building the android system resources
5990                     outValue->data = rid;
5991                     return true;
5992                 }
5993             }
5994         }
5995 
5996         if (accessor != NULL) {
5997             accessor->reportError(accessorCookie, "No resource found that matches the given name");
5998         }
5999         return false;
6000     }
6001 
6002     if (stringToInt(s, len, outValue)) {
6003         if ((attrType&ResTable_map::TYPE_INTEGER) == 0) {
6004             // If this type does not allow integers, but does allow floats,
6005             // fall through on this error case because the float type should
6006             // be able to accept any integer value.
6007             if (!canStringCoerce && (attrType&ResTable_map::TYPE_FLOAT) == 0) {
6008                 if (accessor != NULL) {
6009                     accessor->reportError(accessorCookie, "Integer types not allowed");
6010                 }
6011                 return false;
6012             }
6013         } else {
6014             if (((int32_t)outValue->data) < ((int32_t)attrMin)
6015                     || ((int32_t)outValue->data) > ((int32_t)attrMax)) {
6016                 if (accessor != NULL) {
6017                     accessor->reportError(accessorCookie, "Integer value out of range");
6018                 }
6019                 return false;
6020             }
6021             return true;
6022         }
6023     }
6024 
6025     if (stringToFloat(s, len, outValue)) {
6026         if (outValue->dataType == Res_value::TYPE_DIMENSION) {
6027             if ((attrType&ResTable_map::TYPE_DIMENSION) != 0) {
6028                 return true;
6029             }
6030             if (!canStringCoerce) {
6031                 if (accessor != NULL) {
6032                     accessor->reportError(accessorCookie, "Dimension types not allowed");
6033                 }
6034                 return false;
6035             }
6036         } else if (outValue->dataType == Res_value::TYPE_FRACTION) {
6037             if ((attrType&ResTable_map::TYPE_FRACTION) != 0) {
6038                 return true;
6039             }
6040             if (!canStringCoerce) {
6041                 if (accessor != NULL) {
6042                     accessor->reportError(accessorCookie, "Fraction types not allowed");
6043                 }
6044                 return false;
6045             }
6046         } else if ((attrType&ResTable_map::TYPE_FLOAT) == 0) {
6047             if (!canStringCoerce) {
6048                 if (accessor != NULL) {
6049                     accessor->reportError(accessorCookie, "Float types not allowed");
6050                 }
6051                 return false;
6052             }
6053         } else {
6054             return true;
6055         }
6056     }
6057 
6058     if (len == 4) {
6059         if ((s[0] == 't' || s[0] == 'T') &&
6060             (s[1] == 'r' || s[1] == 'R') &&
6061             (s[2] == 'u' || s[2] == 'U') &&
6062             (s[3] == 'e' || s[3] == 'E')) {
6063             if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
6064                 if (!canStringCoerce) {
6065                     if (accessor != NULL) {
6066                         accessor->reportError(accessorCookie, "Boolean types not allowed");
6067                     }
6068                     return false;
6069                 }
6070             } else {
6071                 outValue->dataType = outValue->TYPE_INT_BOOLEAN;
6072                 outValue->data = (uint32_t)-1;
6073                 return true;
6074             }
6075         }
6076     }
6077 
6078     if (len == 5) {
6079         if ((s[0] == 'f' || s[0] == 'F') &&
6080             (s[1] == 'a' || s[1] == 'A') &&
6081             (s[2] == 'l' || s[2] == 'L') &&
6082             (s[3] == 's' || s[3] == 'S') &&
6083             (s[4] == 'e' || s[4] == 'E')) {
6084             if ((attrType&ResTable_map::TYPE_BOOLEAN) == 0) {
6085                 if (!canStringCoerce) {
6086                     if (accessor != NULL) {
6087                         accessor->reportError(accessorCookie, "Boolean types not allowed");
6088                     }
6089                     return false;
6090                 }
6091             } else {
6092                 outValue->dataType = outValue->TYPE_INT_BOOLEAN;
6093                 outValue->data = 0;
6094                 return true;
6095             }
6096         }
6097     }
6098 
6099     if ((attrType&ResTable_map::TYPE_ENUM) != 0) {
6100         const ssize_t p = getResourcePackageIndex(attrID);
6101         const bag_entry* bag;
6102         ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
6103         //printf("Got %d for enum\n", cnt);
6104         if (cnt >= 0) {
6105             resource_name rname;
6106             while (cnt > 0) {
6107                 if (!Res_INTERNALID(bag->map.name.ident)) {
6108                     //printf("Trying attr #%08x\n", bag->map.name.ident);
6109                     if (getResourceName(bag->map.name.ident, false, &rname)) {
6110                         #if 0
6111                         printf("Matching %s against %s (0x%08x)\n",
6112                                String8(s, len).c_str(),
6113                                String8(rname.name, rname.nameLen).c_str(),
6114                                bag->map.name.ident);
6115                         #endif
6116                         if (strzcmp16(s, len, rname.name, rname.nameLen) == 0) {
6117                             outValue->dataType = bag->map.value.dataType;
6118                             outValue->data = bag->map.value.data;
6119                             unlockBag(bag);
6120                             return true;
6121                         }
6122                     }
6123 
6124                 }
6125                 bag++;
6126                 cnt--;
6127             }
6128             unlockBag(bag);
6129         }
6130 
6131         if (fromAccessor) {
6132             if (accessor->getAttributeEnum(attrID, s, len, outValue)) {
6133                 return true;
6134             }
6135         }
6136     }
6137 
6138     if ((attrType&ResTable_map::TYPE_FLAGS) != 0) {
6139         const ssize_t p = getResourcePackageIndex(attrID);
6140         const bag_entry* bag;
6141         ssize_t cnt = p >= 0 ? lockBag(attrID, &bag) : -1;
6142         //printf("Got %d for flags\n", cnt);
6143         if (cnt >= 0) {
6144             bool failed = false;
6145             resource_name rname;
6146             outValue->dataType = Res_value::TYPE_INT_HEX;
6147             outValue->data = 0;
6148             const char16_t* end = s + len;
6149             const char16_t* pos = s;
6150             while (pos < end && !failed) {
6151                 const char16_t* start = pos;
6152                 pos++;
6153                 while (pos < end && *pos != '|') {
6154                     pos++;
6155                 }
6156                 //printf("Looking for: %s\n", String8(start, pos-start).c_str());
6157                 const bag_entry* bagi = bag;
6158                 ssize_t i;
6159                 for (i=0; i<cnt; i++, bagi++) {
6160                     if (!Res_INTERNALID(bagi->map.name.ident)) {
6161                         //printf("Trying attr #%08x\n", bagi->map.name.ident);
6162                         if (getResourceName(bagi->map.name.ident, false, &rname)) {
6163                             #if 0
6164                             printf("Matching %s against %s (0x%08x)\n",
6165                                    String8(start,pos-start).c_str(),
6166                                    String8(rname.name, rname.nameLen).c_str(),
6167                                    bagi->map.name.ident);
6168                             #endif
6169                             if (strzcmp16(start, pos-start, rname.name, rname.nameLen) == 0) {
6170                                 outValue->data |= bagi->map.value.data;
6171                                 break;
6172                             }
6173                         }
6174                     }
6175                 }
6176                 if (i >= cnt) {
6177                     // Didn't find this flag identifier.
6178                     failed = true;
6179                 }
6180                 if (pos < end) {
6181                     pos++;
6182                 }
6183             }
6184             unlockBag(bag);
6185             if (!failed) {
6186                 //printf("Final flag value: 0x%lx\n", outValue->data);
6187                 return true;
6188             }
6189         }
6190 
6191 
6192         if (fromAccessor) {
6193             if (accessor->getAttributeFlags(attrID, s, len, outValue)) {
6194                 //printf("Final flag value: 0x%lx\n", outValue->data);
6195                 return true;
6196             }
6197         }
6198     }
6199 
6200     if ((attrType&ResTable_map::TYPE_STRING) == 0) {
6201         if (accessor != NULL) {
6202             accessor->reportError(accessorCookie, "String types not allowed");
6203         }
6204         return false;
6205     }
6206 
6207     // Generic string handling...
6208     outValue->dataType = outValue->TYPE_STRING;
6209     if (outString) {
6210         bool failed = collectString(outString, s, len, preserveSpaces, &errorMsg);
6211         if (accessor != NULL) {
6212             accessor->reportError(accessorCookie, errorMsg);
6213         }
6214         return failed;
6215     }
6216 
6217     return true;
6218 }
6219 
collectString(String16 * outString,const char16_t * s,size_t len,bool preserveSpaces,const char ** outErrorMsg,bool append)6220 bool ResTable::collectString(String16* outString,
6221                              const char16_t* s, size_t len,
6222                              bool preserveSpaces,
6223                              const char** outErrorMsg,
6224                              bool append)
6225 {
6226     String16 tmp;
6227 
6228     char quoted = 0;
6229     const char16_t* p = s;
6230     while (p < (s+len)) {
6231         while (p < (s+len)) {
6232             const char16_t c = *p;
6233             if (c == '\\') {
6234                 break;
6235             }
6236             if (!preserveSpaces) {
6237                 if (quoted == 0 && isspace16(c)
6238                     && (c != ' ' || isspace16(*(p+1)))) {
6239                     break;
6240                 }
6241                 if (c == '"' && (quoted == 0 || quoted == '"')) {
6242                     break;
6243                 }
6244                 if (c == '\'' && (quoted == 0 || quoted == '\'')) {
6245                     /*
6246                      * In practice, when people write ' instead of \'
6247                      * in a string, they are doing it by accident
6248                      * instead of really meaning to use ' as a quoting
6249                      * character.  Warn them so they don't lose it.
6250                      */
6251                     if (outErrorMsg) {
6252                         *outErrorMsg = "Apostrophe not preceded by \\";
6253                     }
6254                     return false;
6255                 }
6256             }
6257             p++;
6258         }
6259         if (p < (s+len)) {
6260             if (p > s) {
6261                 tmp.append(String16(s, p-s));
6262             }
6263             if (!preserveSpaces && (*p == '"' || *p == '\'')) {
6264                 if (quoted == 0) {
6265                     quoted = *p;
6266                 } else {
6267                     quoted = 0;
6268                 }
6269                 p++;
6270             } else if (!preserveSpaces && isspace16(*p)) {
6271                 // Space outside of a quote -- consume all spaces and
6272                 // leave a single plain space char.
6273                 tmp.append(String16(" "));
6274                 p++;
6275                 while (p < (s+len) && isspace16(*p)) {
6276                     p++;
6277                 }
6278             } else if (*p == '\\') {
6279                 p++;
6280                 if (p < (s+len)) {
6281                     switch (*p) {
6282                     case 't':
6283                         tmp.append(String16("\t"));
6284                         break;
6285                     case 'n':
6286                         tmp.append(String16("\n"));
6287                         break;
6288                     case '#':
6289                         tmp.append(String16("#"));
6290                         break;
6291                     case '@':
6292                         tmp.append(String16("@"));
6293                         break;
6294                     case '?':
6295                         tmp.append(String16("?"));
6296                         break;
6297                     case '"':
6298                         tmp.append(String16("\""));
6299                         break;
6300                     case '\'':
6301                         tmp.append(String16("'"));
6302                         break;
6303                     case '\\':
6304                         tmp.append(String16("\\"));
6305                         break;
6306                     case 'u':
6307                     {
6308                         char16_t chr = 0;
6309                         int i = 0;
6310                         while (i < 4 && p[1] != 0) {
6311                             p++;
6312                             i++;
6313                             int c;
6314                             if (*p >= '0' && *p <= '9') {
6315                                 c = *p - '0';
6316                             } else if (*p >= 'a' && *p <= 'f') {
6317                                 c = *p - 'a' + 10;
6318                             } else if (*p >= 'A' && *p <= 'F') {
6319                                 c = *p - 'A' + 10;
6320                             } else {
6321                                 if (outErrorMsg) {
6322                                     *outErrorMsg = "Bad character in \\u unicode escape sequence";
6323                                 }
6324                                 return false;
6325                             }
6326                             chr = (chr<<4) | c;
6327                         }
6328                         tmp.append(String16(&chr, 1));
6329                     } break;
6330                     default:
6331                         // ignore unknown escape chars.
6332                         break;
6333                     }
6334                     p++;
6335                 }
6336             }
6337             len -= (p-s);
6338             s = p;
6339         }
6340     }
6341 
6342     if (tmp.size() != 0) {
6343         if (len > 0) {
6344             tmp.append(String16(s, len));
6345         }
6346         if (append) {
6347             outString->append(tmp);
6348         } else {
6349             *outString = tmp;
6350         }
6351     } else {
6352         if (append) {
6353             outString->append(String16(s, len));
6354         } else {
6355             *outString = String16(s, len);
6356         }
6357     }
6358 
6359     return true;
6360 }
6361 
getBasePackageCount() const6362 size_t ResTable::getBasePackageCount() const
6363 {
6364     if (mError != NO_ERROR) {
6365         return 0;
6366     }
6367     return mPackageGroups.size();
6368 }
6369 
getBasePackageName(size_t idx) const6370 const String16 ResTable::getBasePackageName(size_t idx) const
6371 {
6372     if (mError != NO_ERROR) {
6373         return String16();
6374     }
6375     LOG_FATAL_IF(idx >= mPackageGroups.size(),
6376                  "Requested package index %d past package count %d",
6377                  (int)idx, (int)mPackageGroups.size());
6378     return mPackageGroups[idx]->name;
6379 }
6380 
getBasePackageId(size_t idx) const6381 uint32_t ResTable::getBasePackageId(size_t idx) const
6382 {
6383     if (mError != NO_ERROR) {
6384         return 0;
6385     }
6386     LOG_FATAL_IF(idx >= mPackageGroups.size(),
6387                  "Requested package index %d past package count %d",
6388                  (int)idx, (int)mPackageGroups.size());
6389     return mPackageGroups[idx]->id;
6390 }
6391 
getLastTypeIdForPackage(size_t idx) const6392 uint32_t ResTable::getLastTypeIdForPackage(size_t idx) const
6393 {
6394     if (mError != NO_ERROR) {
6395         return 0;
6396     }
6397     LOG_FATAL_IF(idx >= mPackageGroups.size(),
6398             "Requested package index %d past package count %d",
6399             (int)idx, (int)mPackageGroups.size());
6400     const PackageGroup* const group = mPackageGroups[idx];
6401     return group->largestTypeId;
6402 }
6403 
getTableCount() const6404 size_t ResTable::getTableCount() const
6405 {
6406     return mHeaders.size();
6407 }
6408 
getTableStringBlock(size_t index) const6409 const ResStringPool* ResTable::getTableStringBlock(size_t index) const
6410 {
6411     return &mHeaders[index]->values;
6412 }
6413 
getTableCookie(size_t index) const6414 int32_t ResTable::getTableCookie(size_t index) const
6415 {
6416     return mHeaders[index]->cookie;
6417 }
6418 
getDynamicRefTableForCookie(int32_t cookie) const6419 const DynamicRefTable* ResTable::getDynamicRefTableForCookie(int32_t cookie) const
6420 {
6421     const size_t N = mPackageGroups.size();
6422     for (size_t i = 0; i < N; i++) {
6423         const PackageGroup* pg = mPackageGroups[i];
6424         size_t M = pg->packages.size();
6425         for (size_t j = 0; j < M; j++) {
6426             if (pg->packages[j]->header->cookie == cookie) {
6427                 return &pg->dynamicRefTable;
6428             }
6429         }
6430     }
6431     return NULL;
6432 }
6433 
compareResTableConfig(const ResTable_config & a,const ResTable_config & b)6434 static bool compareResTableConfig(const ResTable_config& a, const ResTable_config& b) {
6435     return a.compare(b) < 0;
6436 }
6437 
6438 template <typename Func>
forEachConfiguration(bool ignoreMipmap,bool ignoreAndroidPackage,bool includeSystemConfigs,const Func & f) const6439 void ResTable::forEachConfiguration(bool ignoreMipmap, bool ignoreAndroidPackage,
6440                                     bool includeSystemConfigs, const Func& f) const {
6441     const size_t packageCount = mPackageGroups.size();
6442     const String16 android("android");
6443     for (size_t i = 0; i < packageCount; i++) {
6444         const PackageGroup* packageGroup = mPackageGroups[i];
6445         if (ignoreAndroidPackage && android == packageGroup->name) {
6446             continue;
6447         }
6448         if (!includeSystemConfigs && packageGroup->isSystemAsset) {
6449             continue;
6450         }
6451         const size_t typeCount = packageGroup->types.size();
6452         for (size_t j = 0; j < typeCount; j++) {
6453             const TypeList& typeList = packageGroup->types[j];
6454             const size_t numTypes = typeList.size();
6455             for (size_t k = 0; k < numTypes; k++) {
6456                 const Type* type = typeList[k];
6457                 const ResStringPool& typeStrings = type->package->typeStrings;
6458                 const base::expected<String8, NullOrIOError> typeStr = typeStrings.string8ObjectAt(
6459                     type->typeSpec->id - 1);
6460                 if (ignoreMipmap && typeStr.has_value() && *typeStr == "mipmap") {
6461                     continue;
6462                 }
6463 
6464                 const size_t numConfigs = type->configs.size();
6465                 for (size_t m = 0; m < numConfigs; m++) {
6466                     const ResTable_type* config = type->configs[m];
6467                     ResTable_config cfg;
6468                     memset(&cfg, 0, sizeof(ResTable_config));
6469                     cfg.copyFromDtoH(config->config);
6470 
6471                     f(cfg);
6472                 }
6473             }
6474         }
6475     }
6476 }
6477 
getConfigurations(Vector<ResTable_config> * configs,bool ignoreMipmap,bool ignoreAndroidPackage,bool includeSystemConfigs) const6478 void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
6479                                  bool ignoreAndroidPackage, bool includeSystemConfigs) const {
6480     auto func = [&](const ResTable_config& cfg) {
6481         const auto beginIter = configs->begin();
6482         const auto endIter = configs->end();
6483 
6484         auto iter = std::lower_bound(beginIter, endIter, cfg, compareResTableConfig);
6485         if (iter == endIter || iter->compare(cfg) != 0) {
6486             configs->insertAt(cfg, std::distance(beginIter, iter));
6487         }
6488     };
6489     forEachConfiguration(ignoreMipmap, ignoreAndroidPackage, includeSystemConfigs, func);
6490 }
6491 
compareString8AndCString(const String8 & str,const char * cStr)6492 static bool compareString8AndCString(const String8& str, const char* cStr) {
6493     return strcmp(str.c_str(), cStr) < 0;
6494 }
6495 
getLocales(Vector<String8> * locales,bool includeSystemLocales,bool mergeEquivalentLangs) const6496 void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales,
6497                           bool mergeEquivalentLangs) const {
6498     char locale[RESTABLE_MAX_LOCALE_LEN];
6499 
6500     forEachConfiguration(false, false, includeSystemLocales, [&](const ResTable_config& cfg) {
6501         cfg.getBcp47Locale(locale, mergeEquivalentLangs /* canonicalize if merging */);
6502 
6503         const auto beginIter = locales->begin();
6504         const auto endIter = locales->end();
6505 
6506         auto iter = std::lower_bound(beginIter, endIter, locale, compareString8AndCString);
6507         if (iter == endIter || strcmp(iter->c_str(), locale) != 0) {
6508             locales->insertAt(String8(locale), std::distance(beginIter, iter));
6509         }
6510     });
6511 }
6512 
StringPoolRef(const ResStringPool * pool,uint32_t index)6513 StringPoolRef::StringPoolRef(const ResStringPool* pool, uint32_t index)
6514     : mPool(pool), mIndex(index) {}
6515 
string8() const6516 base::expected<StringPiece, NullOrIOError> StringPoolRef::string8() const {
6517     if (LIKELY(mPool != NULL)) {
6518         return mPool->string8At(mIndex);
6519     }
6520     return base::unexpected(std::nullopt);
6521 }
6522 
string16() const6523 base::expected<StringPiece16, NullOrIOError> StringPoolRef::string16() const {
6524     if (LIKELY(mPool != NULL)) {
6525         return mPool->stringAt(mIndex);
6526     }
6527     return base::unexpected(std::nullopt);
6528 }
6529 
getResourceFlags(uint32_t resID,uint32_t * outFlags) const6530 bool ResTable::getResourceFlags(uint32_t resID, uint32_t* outFlags) const {
6531     if (mError != NO_ERROR) {
6532         return false;
6533     }
6534 
6535     const ssize_t p = getResourcePackageIndex(resID);
6536     const int t = Res_GETTYPE(resID);
6537     const int e = Res_GETENTRY(resID);
6538 
6539     if (p < 0) {
6540         if (Res_GETPACKAGE(resID)+1 == 0) {
6541             ALOGW("No package identifier when getting flags for resource number 0x%08x", resID);
6542         } else {
6543             ALOGW("No known package when getting flags for resource number 0x%08x", resID);
6544         }
6545         return false;
6546     }
6547     if (t < 0) {
6548         ALOGW("No type identifier when getting flags for resource number 0x%08x", resID);
6549         return false;
6550     }
6551 
6552     const PackageGroup* const grp = mPackageGroups[p];
6553     if (grp == NULL) {
6554         ALOGW("Bad identifier when getting flags for resource number 0x%08x", resID);
6555         return false;
6556     }
6557 
6558     Entry entry;
6559     status_t err = getEntry(grp, t, e, NULL, &entry);
6560     if (err != NO_ERROR) {
6561         return false;
6562     }
6563 
6564     *outFlags = entry.specFlags;
6565     return true;
6566 }
6567 
isPackageDynamic(uint8_t packageID) const6568 bool ResTable::isPackageDynamic(uint8_t packageID) const {
6569   if (mError != NO_ERROR) {
6570       return false;
6571   }
6572   if (packageID == 0) {
6573       ALOGW("Invalid package number 0x%08x", packageID);
6574       return false;
6575   }
6576 
6577   const ssize_t p = getResourcePackageIndexFromPackage(packageID);
6578 
6579   if (p < 0) {
6580       ALOGW("Unknown package number 0x%08x", packageID);
6581       return false;
6582   }
6583 
6584   const PackageGroup* const grp = mPackageGroups[p];
6585   if (grp == NULL) {
6586       ALOGW("Bad identifier for package number 0x%08x", packageID);
6587       return false;
6588   }
6589 
6590   return grp->isDynamic;
6591 }
6592 
isResourceDynamic(uint32_t resID) const6593 bool ResTable::isResourceDynamic(uint32_t resID) const {
6594     if (mError != NO_ERROR) {
6595         return false;
6596     }
6597 
6598     const ssize_t p = getResourcePackageIndex(resID);
6599     const int t = Res_GETTYPE(resID);
6600     const int e = Res_GETENTRY(resID);
6601 
6602     if (p < 0) {
6603         if (Res_GETPACKAGE(resID)+1 == 0) {
6604             ALOGW("No package identifier for resource number 0x%08x", resID);
6605         } else {
6606             ALOGW("No known package for resource number 0x%08x", resID);
6607         }
6608         return false;
6609     }
6610     if (t < 0) {
6611         ALOGW("No type identifier for resource number 0x%08x", resID);
6612         return false;
6613     }
6614 
6615     const PackageGroup* const grp = mPackageGroups[p];
6616     if (grp == NULL) {
6617         ALOGW("Bad identifier for resource number 0x%08x", resID);
6618         return false;
6619     }
6620 
6621     Entry entry;
6622     status_t err = getEntry(grp, t, e, NULL, &entry);
6623     if (err != NO_ERROR) {
6624         return false;
6625     }
6626 
6627     return grp->isDynamic;
6628 }
6629 
keyCompare(const ResTable_sparseTypeEntry & entry,uint16_t entryIdx)6630 static bool keyCompare(const ResTable_sparseTypeEntry& entry , uint16_t entryIdx) {
6631   return dtohs(entry.idx) < entryIdx;
6632 }
6633 
getEntry(const PackageGroup * packageGroup,int typeIndex,int entryIndex,const ResTable_config * config,Entry * outEntry) const6634 status_t ResTable::getEntry(
6635         const PackageGroup* packageGroup, int typeIndex, int entryIndex,
6636         const ResTable_config* config,
6637         Entry* outEntry) const
6638 {
6639     const TypeList& typeList = packageGroup->types[typeIndex];
6640     if (typeList.isEmpty()) {
6641         ALOGV("Skipping entry type index 0x%02x because type is NULL!\n", typeIndex);
6642         return BAD_TYPE;
6643     }
6644 
6645     const ResTable_type* bestType = NULL;
6646     uint32_t bestOffset = ResTable_type::NO_ENTRY;
6647     const Package* bestPackage = NULL;
6648     uint32_t specFlags = 0;
6649     uint8_t actualTypeIndex = typeIndex;
6650     ResTable_config bestConfig;
6651     memset(&bestConfig, 0, sizeof(bestConfig));
6652 
6653     // Iterate over the Types of each package.
6654     const size_t typeCount = typeList.size();
6655     for (size_t i = 0; i < typeCount; i++) {
6656         const Type* const typeSpec = typeList[i];
6657 
6658         int realEntryIndex = entryIndex;
6659         int realTypeIndex = typeIndex;
6660         bool currentTypeIsOverlay = false;
6661 
6662         // Runtime overlay packages provide a mapping of app resource
6663         // ID to package resource ID.
6664         if (typeSpec->idmapEntries.hasEntries()) {
6665             uint16_t overlayEntryIndex;
6666             if (typeSpec->idmapEntries.lookup(entryIndex, &overlayEntryIndex) != NO_ERROR) {
6667                 // No such mapping exists
6668                 continue;
6669             }
6670             realEntryIndex = overlayEntryIndex;
6671             realTypeIndex = typeSpec->idmapEntries.overlayTypeId() - 1;
6672             currentTypeIsOverlay = true;
6673         }
6674 
6675         // Check that the entry idx is within range of the declared entry count (ResTable_typeSpec).
6676         // Particular types (ResTable_type) may be encoded with sparse entries, and so their
6677         // entryCount do not need to match.
6678         if (static_cast<size_t>(realEntryIndex) >= typeSpec->entryCount) {
6679             ALOGW("For resource 0x%08x, entry index(%d) is beyond type entryCount(%d)",
6680                     Res_MAKEID(packageGroup->id - 1, typeIndex, entryIndex),
6681                     entryIndex, static_cast<int>(typeSpec->entryCount));
6682             // We should normally abort here, but some legacy apps declare
6683             // resources in the 'android' package (old bug in AAPT).
6684             continue;
6685         }
6686 
6687         // Aggregate all the flags for each package that defines this entry.
6688         if (typeSpec->typeSpecFlags != NULL) {
6689             specFlags |= dtohl(typeSpec->typeSpecFlags[realEntryIndex]);
6690         } else {
6691             specFlags = -1;
6692         }
6693 
6694         const Vector<const ResTable_type*>* candidateConfigs = &typeSpec->configs;
6695 
6696         std::shared_ptr<Vector<const ResTable_type*>> filteredConfigs;
6697         if (config && memcmp(&mParams, config, sizeof(mParams)) == 0) {
6698             // Grab the lock first so we can safely get the current filtered list.
6699             AutoMutex _lock(mFilteredConfigLock);
6700 
6701             // This configuration is equal to the one we have previously cached for,
6702             // so use the filtered configs.
6703 
6704             const TypeCacheEntry& cacheEntry = packageGroup->typeCacheEntries[typeIndex];
6705             if (i < cacheEntry.filteredConfigs.size()) {
6706                 if (cacheEntry.filteredConfigs[i]) {
6707                     // Grab a reference to the shared_ptr so it doesn't get destroyed while
6708                     // going through this list.
6709                     filteredConfigs = cacheEntry.filteredConfigs[i];
6710 
6711                     // Use this filtered list.
6712                     candidateConfigs = filteredConfigs.get();
6713                 }
6714             }
6715         }
6716 
6717         const size_t numConfigs = candidateConfigs->size();
6718         for (size_t c = 0; c < numConfigs; c++) {
6719             const ResTable_type* const thisType = candidateConfigs->itemAt(c);
6720             if (thisType == NULL) {
6721                 continue;
6722             }
6723 
6724             ResTable_config thisConfig;
6725             thisConfig.copyFromDtoH(thisType->config);
6726 
6727             // Check to make sure this one is valid for the current parameters.
6728             if (config != NULL && !thisConfig.match(*config)) {
6729                 continue;
6730             }
6731 
6732             const uint32_t* const eindex = reinterpret_cast<const uint32_t*>(
6733                     reinterpret_cast<const uint8_t*>(thisType) + dtohs(thisType->header.headerSize));
6734 
6735             uint32_t thisOffset;
6736 
6737             // Check if there is the desired entry in this type.
6738             if (thisType->flags & ResTable_type::FLAG_SPARSE) {
6739                 // This is encoded as a sparse map, so perform a binary search.
6740                 const ResTable_sparseTypeEntry* sparseIndices =
6741                         reinterpret_cast<const ResTable_sparseTypeEntry*>(eindex);
6742                 const ResTable_sparseTypeEntry* result = std::lower_bound(
6743                         sparseIndices, sparseIndices + dtohl(thisType->entryCount), realEntryIndex,
6744                         keyCompare);
6745                 if (result == sparseIndices + dtohl(thisType->entryCount)
6746                         || dtohs(result->idx) != realEntryIndex) {
6747                     // No entry found.
6748                     continue;
6749                 }
6750 
6751                 // Extract the offset from the entry. Each offset must be a multiple of 4
6752                 // so we store it as the real offset divided by 4.
6753                 thisOffset = dtohs(result->offset) * 4u;
6754             } else {
6755                 if (static_cast<uint32_t>(realEntryIndex) >= dtohl(thisType->entryCount)) {
6756                     // Entry does not exist.
6757                     continue;
6758                 }
6759                 if (thisType->flags & ResTable_type::FLAG_OFFSET16) {
6760                     auto eindex16 = reinterpret_cast<const uint16_t*>(eindex);
6761                     thisOffset = offset_from16(eindex16[realEntryIndex]);
6762                 } else {
6763                     thisOffset = dtohl(eindex[realEntryIndex]);
6764                 }
6765             }
6766 
6767             if (thisOffset == ResTable_type::NO_ENTRY) {
6768                 // There is no entry for this index and configuration.
6769                 continue;
6770             }
6771 
6772             if (bestType != NULL) {
6773                 // Check if this one is less specific than the last found.  If so,
6774                 // we will skip it.  We check starting with things we most care
6775                 // about to those we least care about.
6776                 if (!thisConfig.isBetterThan(bestConfig, config)) {
6777                     if (!currentTypeIsOverlay || thisConfig.compare(bestConfig) != 0) {
6778                         continue;
6779                     }
6780                 }
6781             }
6782 
6783             bestType = thisType;
6784             bestOffset = thisOffset;
6785             bestConfig = thisConfig;
6786             bestPackage = typeSpec->package;
6787             actualTypeIndex = realTypeIndex;
6788 
6789             // If no config was specified, any type will do, so skip
6790             if (config == NULL) {
6791                 break;
6792             }
6793         }
6794     }
6795 
6796     if (bestType == NULL) {
6797         return BAD_INDEX;
6798     }
6799 
6800     bestOffset += dtohl(bestType->entriesStart);
6801 
6802     if (bestOffset > (dtohl(bestType->header.size)-sizeof(ResTable_entry))) {
6803         ALOGW("ResTable_entry at 0x%x is beyond type chunk data 0x%x",
6804                 bestOffset, dtohl(bestType->header.size));
6805         return BAD_TYPE;
6806     }
6807     if ((bestOffset & 0x3) != 0) {
6808         ALOGW("ResTable_entry at 0x%x is not on an integer boundary", bestOffset);
6809         return BAD_TYPE;
6810     }
6811 
6812     const ResTable_entry* const entry = reinterpret_cast<const ResTable_entry*>(
6813             reinterpret_cast<const uint8_t*>(bestType) + bestOffset);
6814     if (entry->size() < sizeof(*entry)) {
6815         ALOGW("ResTable_entry size 0x%zx is too small", entry->size());
6816         return BAD_TYPE;
6817     }
6818 
6819     if (outEntry != NULL) {
6820         outEntry->entry = entry;
6821         outEntry->config = bestConfig;
6822         outEntry->type = bestType;
6823         outEntry->specFlags = specFlags;
6824         outEntry->package = bestPackage;
6825         outEntry->typeStr = StringPoolRef(&bestPackage->typeStrings, actualTypeIndex - bestPackage->typeIdOffset);
6826         outEntry->keyStr = StringPoolRef(&bestPackage->keyStrings, entry->key());
6827     }
6828     return NO_ERROR;
6829 }
6830 
parsePackage(const ResTable_package * const pkg,const Header * const header,bool appAsLib,bool isSystemAsset)6831 status_t ResTable::parsePackage(const ResTable_package* const pkg,
6832                                 const Header* const header, bool appAsLib, bool isSystemAsset)
6833 {
6834     const uint8_t* base = (const uint8_t*)pkg;
6835     status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
6836                                   header->dataEnd, "ResTable_package");
6837     if (err != NO_ERROR) {
6838         return (mError=err);
6839     }
6840 
6841     const uint32_t pkgSize = dtohl(pkg->header.size);
6842 
6843     if (dtohl(pkg->typeStrings) >= pkgSize) {
6844         ALOGW("ResTable_package type strings at 0x%x are past chunk size 0x%x.",
6845              dtohl(pkg->typeStrings), pkgSize);
6846         return (mError=BAD_TYPE);
6847     }
6848     if ((dtohl(pkg->typeStrings)&0x3) != 0) {
6849         ALOGW("ResTable_package type strings at 0x%x is not on an integer boundary.",
6850              dtohl(pkg->typeStrings));
6851         return (mError=BAD_TYPE);
6852     }
6853     if (dtohl(pkg->keyStrings) >= pkgSize) {
6854         ALOGW("ResTable_package key strings at 0x%x are past chunk size 0x%x.",
6855              dtohl(pkg->keyStrings), pkgSize);
6856         return (mError=BAD_TYPE);
6857     }
6858     if ((dtohl(pkg->keyStrings)&0x3) != 0) {
6859         ALOGW("ResTable_package key strings at 0x%x is not on an integer boundary.",
6860              dtohl(pkg->keyStrings));
6861         return (mError=BAD_TYPE);
6862     }
6863 
6864     uint32_t id = dtohl(pkg->id);
6865     KeyedVector<uint8_t, IdmapEntries> idmapEntries;
6866 
6867     if (header->resourceIDMap != NULL) {
6868         uint8_t targetPackageId = 0;
6869         status_t err = parseIdmap(header->resourceIDMap, header->resourceIDMapSize, &targetPackageId, &idmapEntries);
6870         if (err != NO_ERROR) {
6871             ALOGW("Overlay is broken");
6872             return (mError=err);
6873         }
6874         id = targetPackageId;
6875     }
6876 
6877     bool isDynamic = false;
6878     if (id >= 256) {
6879         LOG_ALWAYS_FATAL("Package id out of range");
6880         return NO_ERROR;
6881     } else if (id == 0 || (id == 0x7f && appAsLib) || isSystemAsset) {
6882         // This is a library or a system asset, so assign an ID
6883         id = mNextPackageId++;
6884         isDynamic = true;
6885     }
6886 
6887     PackageGroup* group = NULL;
6888     Package* package = new Package(this, header, pkg);
6889     if (package == NULL) {
6890         return (mError=NO_MEMORY);
6891     }
6892 
6893     err = package->typeStrings.setTo(base+dtohl(pkg->typeStrings),
6894                                    header->dataEnd-(base+dtohl(pkg->typeStrings)));
6895     if (err != NO_ERROR) {
6896         delete group;
6897         delete package;
6898         return (mError=err);
6899     }
6900 
6901     err = package->keyStrings.setTo(base+dtohl(pkg->keyStrings),
6902                                   header->dataEnd-(base+dtohl(pkg->keyStrings)));
6903     if (err != NO_ERROR) {
6904         delete group;
6905         delete package;
6906         return (mError=err);
6907     }
6908 
6909     size_t idx = mPackageMap[id];
6910     if (idx == 0) {
6911         idx = mPackageGroups.size() + 1;
6912         char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
6913         strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
6914         group = new PackageGroup(this, String16(tmpName), id, appAsLib, isSystemAsset, isDynamic);
6915         if (group == NULL) {
6916             delete package;
6917             return (mError=NO_MEMORY);
6918         }
6919 
6920         err = mPackageGroups.add(group);
6921         if (err < NO_ERROR) {
6922             return (mError=err);
6923         }
6924 
6925         mPackageMap[id] = static_cast<uint8_t>(idx);
6926 
6927         // Find all packages that reference this package
6928         size_t N = mPackageGroups.size();
6929         for (size_t i = 0; i < N; i++) {
6930             mPackageGroups[i]->dynamicRefTable.addMapping(
6931                     group->name, static_cast<uint8_t>(group->id));
6932         }
6933     } else {
6934         group = mPackageGroups.itemAt(idx - 1);
6935         if (group == NULL) {
6936             return (mError=UNKNOWN_ERROR);
6937         }
6938     }
6939 
6940     err = group->packages.add(package);
6941     if (err < NO_ERROR) {
6942         return (mError=err);
6943     }
6944 
6945     // Iterate through all chunks.
6946     const ResChunk_header* chunk =
6947         (const ResChunk_header*)(((const uint8_t*)pkg)
6948                                  + dtohs(pkg->header.headerSize));
6949     const uint8_t* endPos = ((const uint8_t*)pkg) + dtohs(pkg->header.size);
6950     while (((const uint8_t*)chunk) <= (endPos-sizeof(ResChunk_header)) &&
6951            ((const uint8_t*)chunk) <= (endPos-dtohl(chunk->size))) {
6952         if (kDebugTableNoisy) {
6953             ALOGV("PackageChunk: type=0x%x, headerSize=0x%x, size=0x%x, pos=%p\n",
6954                     dtohs(chunk->type), dtohs(chunk->headerSize), dtohl(chunk->size),
6955                     (void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
6956         }
6957         const size_t csize = dtohl(chunk->size);
6958         const uint16_t ctype = dtohs(chunk->type);
6959         if (ctype == RES_TABLE_TYPE_SPEC_TYPE) {
6960             const ResTable_typeSpec* typeSpec = (const ResTable_typeSpec*)(chunk);
6961             err = validate_chunk(&typeSpec->header, sizeof(*typeSpec),
6962                                  endPos, "ResTable_typeSpec");
6963             if (err != NO_ERROR) {
6964                 return (mError=err);
6965             }
6966 
6967             const size_t typeSpecSize = dtohl(typeSpec->header.size);
6968             const size_t newEntryCount = dtohl(typeSpec->entryCount);
6969 
6970             if (kDebugLoadTableNoisy) {
6971                 ALOGI("TypeSpec off %p: type=0x%x, headerSize=0x%x, size=%p\n",
6972                         (void*)(base-(const uint8_t*)chunk),
6973                         dtohs(typeSpec->header.type),
6974                         dtohs(typeSpec->header.headerSize),
6975                         (void*)typeSpecSize);
6976             }
6977             // look for block overrun or int overflow when multiplying by 4
6978             if ((dtohl(typeSpec->entryCount) > (INT32_MAX/sizeof(uint32_t))
6979                     || dtohs(typeSpec->header.headerSize)+(sizeof(uint32_t)*newEntryCount)
6980                     > typeSpecSize)) {
6981                 ALOGW("ResTable_typeSpec entry index to %p extends beyond chunk end %p.",
6982                         (void*)(dtohs(typeSpec->header.headerSize) + (sizeof(uint32_t)*newEntryCount)),
6983                         (void*)typeSpecSize);
6984                 return (mError=BAD_TYPE);
6985             }
6986 
6987             if (typeSpec->id == 0) {
6988                 ALOGW("ResTable_type has an id of 0.");
6989                 return (mError=BAD_TYPE);
6990             }
6991 
6992             if (newEntryCount > 0) {
6993                 bool addToType = true;
6994                 uint8_t typeIndex = typeSpec->id - 1;
6995                 ssize_t idmapIndex = idmapEntries.indexOfKey(typeSpec->id);
6996                 if (idmapIndex >= 0) {
6997                     typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
6998                 } else if (header->resourceIDMap != NULL) {
6999                     // This is an overlay, but the types in this overlay are not
7000                     // overlaying anything according to the idmap. We can skip these
7001                     // as they will otherwise conflict with the other resources in the package
7002                     // without a mapping.
7003                     addToType = false;
7004                 }
7005 
7006                 if (addToType) {
7007                     TypeList& typeList = group->types.editItemAt(typeIndex);
7008                     if (!typeList.isEmpty()) {
7009                         const Type* existingType = typeList[0];
7010                         if (existingType->entryCount != newEntryCount && idmapIndex < 0) {
7011                             ALOGW("ResTable_typeSpec entry count inconsistent: "
7012                                   "given %d, previously %d",
7013                                   (int) newEntryCount, (int) existingType->entryCount);
7014                             // We should normally abort here, but some legacy apps declare
7015                             // resources in the 'android' package (old bug in AAPT).
7016                         }
7017                     }
7018 
7019                     Type* t = new Type(header, package, newEntryCount);
7020                     t->typeSpec = typeSpec;
7021                     t->typeSpecFlags = (const uint32_t*)(
7022                             ((const uint8_t*)typeSpec) + dtohs(typeSpec->header.headerSize));
7023                     if (idmapIndex >= 0) {
7024                         t->idmapEntries = idmapEntries[idmapIndex];
7025                     }
7026                     typeList.add(t);
7027                     group->largestTypeId = max(group->largestTypeId, typeSpec->id);
7028                 }
7029             } else {
7030                 ALOGV("Skipping empty ResTable_typeSpec for type %d", typeSpec->id);
7031             }
7032 
7033         } else if (ctype == RES_TABLE_TYPE_TYPE) {
7034             const ResTable_type* type = (const ResTable_type*)(chunk);
7035             err = validate_chunk(&type->header, sizeof(*type)-sizeof(ResTable_config)+4,
7036                                  endPos, "ResTable_type");
7037             if (err != NO_ERROR) {
7038                 return (mError=err);
7039             }
7040 
7041             const uint32_t typeSize = dtohl(type->header.size);
7042             const size_t newEntryCount = dtohl(type->entryCount);
7043             const size_t entrySize = type->flags & ResTable_type::FLAG_OFFSET16 ?
7044                                        sizeof(uint16_t) : sizeof(uint32_t);
7045             if (kDebugLoadTableNoisy) {
7046                 printf("Type off %p: type=0x%x, headerSize=0x%x, size=%u\n",
7047                         (void*)(base-(const uint8_t*)chunk),
7048                         dtohs(type->header.type),
7049                         dtohs(type->header.headerSize),
7050                         typeSize);
7051             }
7052             if (dtohs(type->header.headerSize)+(entrySize*newEntryCount) > typeSize) {
7053                 ALOGW("ResTable_type entry index to %p extends beyond chunk end 0x%x.",
7054                         (void*)(dtohs(type->header.headerSize) + (entrySize*newEntryCount)),
7055                         typeSize);
7056                 return (mError=BAD_TYPE);
7057             }
7058 
7059             if (newEntryCount != 0
7060                 && dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) {
7061                 ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.",
7062                      dtohl(type->entriesStart), typeSize);
7063                 return (mError=BAD_TYPE);
7064             }
7065 
7066             if (type->id == 0) {
7067                 ALOGW("ResTable_type has an id of 0.");
7068                 return (mError=BAD_TYPE);
7069             }
7070 
7071             if (newEntryCount > 0) {
7072                 bool addToType = true;
7073                 uint8_t typeIndex = type->id - 1;
7074                 ssize_t idmapIndex = idmapEntries.indexOfKey(type->id);
7075                 if (idmapIndex >= 0) {
7076                     typeIndex = idmapEntries[idmapIndex].targetTypeId() - 1;
7077                 } else if (header->resourceIDMap != NULL) {
7078                     // This is an overlay, but the types in this overlay are not
7079                     // overlaying anything according to the idmap. We can skip these
7080                     // as they will otherwise conflict with the other resources in the package
7081                     // without a mapping.
7082                     addToType = false;
7083                 }
7084 
7085                 if (addToType) {
7086                     TypeList& typeList = group->types.editItemAt(typeIndex);
7087                     if (typeList.isEmpty()) {
7088                         ALOGE("No TypeSpec for type %d", type->id);
7089                         return (mError=BAD_TYPE);
7090                     }
7091 
7092                     Type* t = typeList.editItemAt(typeList.size() - 1);
7093                     if (t->package != package) {
7094                         ALOGE("No TypeSpec for type %d", type->id);
7095                         return (mError=BAD_TYPE);
7096                     }
7097 
7098                     t->configs.add(type);
7099 
7100                     if (kDebugTableGetEntry) {
7101                         ResTable_config thisConfig;
7102                         thisConfig.copyFromDtoH(type->config);
7103                         ALOGI("Adding config to type %d: %s\n", type->id,
7104                                 thisConfig.toString().c_str());
7105                     }
7106                 }
7107             } else {
7108                 ALOGV("Skipping empty ResTable_type for type %d", type->id);
7109             }
7110 
7111         } else if (ctype == RES_TABLE_LIBRARY_TYPE) {
7112 
7113             if (group->dynamicRefTable.entries().size() == 0) {
7114                 const ResTable_lib_header* lib = (const ResTable_lib_header*) chunk;
7115                 status_t err = validate_chunk(&lib->header, sizeof(*lib),
7116                                               endPos, "ResTable_lib_header");
7117                 if (err != NO_ERROR) {
7118                     return (mError=err);
7119                 }
7120 
7121                 err = group->dynamicRefTable.load(lib);
7122                 if (err != NO_ERROR) {
7123                     return (mError=err);
7124                 }
7125 
7126                 // Fill in the reference table with the entries we already know about.
7127                 size_t N = mPackageGroups.size();
7128                 for (size_t i = 0; i < N; i++) {
7129                     group->dynamicRefTable.addMapping(mPackageGroups[i]->name, mPackageGroups[i]->id);
7130                 }
7131             } else {
7132                 ALOGW("Found multiple library tables, ignoring...");
7133             }
7134         } else {
7135             if (ctype == RES_TABLE_OVERLAYABLE_TYPE) {
7136                 package->definesOverlayable = true;
7137             }
7138 
7139             status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
7140                                           endPos, "ResTable_package:unknown");
7141             if (err != NO_ERROR) {
7142                 return (mError=err);
7143             }
7144         }
7145         chunk = (const ResChunk_header*)
7146             (((const uint8_t*)chunk) + csize);
7147     }
7148 
7149     return NO_ERROR;
7150 }
7151 
DynamicRefTable()7152 DynamicRefTable::DynamicRefTable() : DynamicRefTable(0, false) {}
7153 
DynamicRefTable(uint8_t packageId,bool appAsLib)7154 DynamicRefTable::DynamicRefTable(uint8_t packageId, bool appAsLib)
7155     : mLookupTable()
7156     , mAssignedPackageId(packageId)
7157     , mAppAsLib(appAsLib)
7158 {
7159     // Reserved package ids
7160     mLookupTable[APP_PACKAGE_ID] = APP_PACKAGE_ID;
7161     mLookupTable[SYS_PACKAGE_ID] = SYS_PACKAGE_ID;
7162 }
7163 
load(const ResTable_lib_header * const header)7164 status_t DynamicRefTable::load(const ResTable_lib_header* const header)
7165 {
7166     const uint32_t entryCount = dtohl(header->count);
7167     const uint32_t expectedSize = dtohl(header->header.size) - dtohl(header->header.headerSize);
7168     if (entryCount > (expectedSize / sizeof(ResTable_lib_entry))) {
7169         ALOGE("ResTable_lib_header size %u is too small to fit %u entries (x %u).",
7170                 expectedSize, entryCount, (uint32_t)sizeof(ResTable_lib_entry));
7171         return UNKNOWN_ERROR;
7172     }
7173 
7174     const ResTable_lib_entry* entry = (const ResTable_lib_entry*)(((uint8_t*) header) +
7175             dtohl(header->header.headerSize));
7176     for (uint32_t entryIndex = 0; entryIndex < entryCount; entryIndex++) {
7177         uint32_t packageId = dtohl(entry->packageId);
7178         char16_t tmpName[sizeof(entry->packageName) / sizeof(char16_t)];
7179         strcpy16_dtoh(tmpName, entry->packageName, sizeof(entry->packageName) / sizeof(char16_t));
7180         if (kDebugLibNoisy) {
7181             ALOGV("Found lib entry %s with id %d\n", String8(tmpName).c_str(),
7182                     dtohl(entry->packageId));
7183         }
7184         if (packageId >= 256) {
7185             ALOGE("Bad package id 0x%08x", packageId);
7186             return UNKNOWN_ERROR;
7187         }
7188         mEntries.replaceValueFor(String16(tmpName), (uint8_t) packageId);
7189         entry = entry + 1;
7190     }
7191     return NO_ERROR;
7192 }
7193 
addMappings(const DynamicRefTable & other)7194 status_t DynamicRefTable::addMappings(const DynamicRefTable& other) {
7195     if (mAssignedPackageId != other.mAssignedPackageId) {
7196         return UNKNOWN_ERROR;
7197     }
7198 
7199     const size_t entryCount = other.mEntries.size();
7200     for (size_t i = 0; i < entryCount; i++) {
7201         ssize_t index = mEntries.indexOfKey(other.mEntries.keyAt(i));
7202         if (index < 0) {
7203             mEntries.add(String16(other.mEntries.keyAt(i)), other.mEntries[i]);
7204         } else {
7205             if (other.mEntries[i] != mEntries[index]) {
7206                 return UNKNOWN_ERROR;
7207             }
7208         }
7209     }
7210 
7211     // Merge the lookup table. No entry can conflict
7212     // (value of 0 means not set).
7213     for (size_t i = 0; i < 256; i++) {
7214         if (mLookupTable[i] != other.mLookupTable[i]) {
7215             if (mLookupTable[i] == 0) {
7216                 mLookupTable[i] = other.mLookupTable[i];
7217             } else if (other.mLookupTable[i] != 0) {
7218                 return UNKNOWN_ERROR;
7219             }
7220         }
7221     }
7222     return NO_ERROR;
7223 }
7224 
addMapping(const String16 & packageName,uint8_t packageId)7225 status_t DynamicRefTable::addMapping(const String16& packageName, uint8_t packageId)
7226 {
7227     ssize_t index = mEntries.indexOfKey(packageName);
7228     if (index < 0) {
7229         return UNKNOWN_ERROR;
7230     }
7231     mLookupTable[mEntries.valueAt(index)] = packageId;
7232     return NO_ERROR;
7233 }
7234 
addMapping(uint8_t buildPackageId,uint8_t runtimePackageId)7235 void DynamicRefTable::addMapping(uint8_t buildPackageId, uint8_t runtimePackageId) {
7236     mLookupTable[buildPackageId] = runtimePackageId;
7237 }
7238 
lookupResourceId(uint32_t * resId) const7239 status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
7240     uint32_t res = *resId;
7241     if (!Res_VALIDID(res)) {
7242         // Cannot look up a null or invalid id, so no lookup needs to be done.
7243         return NO_ERROR;
7244     }
7245     const size_t packageId = Res_GETPACKAGE(res) + 1;
7246     if (packageId == 0 || (packageId == APP_PACKAGE_ID && mAppAsLib)) {
7247         // The package ID is 0x00. That means that a shared library is accessing
7248         // its own local resource.
7249         // Or if app resource is loaded as shared library, the resource which has
7250         // app package Id is local resources.
7251         // so we fix up those resources with the calling package ID.
7252         *resId = (0xFFFFFF & (*resId)) | (((uint32_t) mAssignedPackageId) << 24);
7253         return NO_ERROR;
7254     }
7255     // All aliases are coming from the framework, and usually have their own separate ID range,
7256     // skipping the whole binary search is much more efficient than not finding anything.
7257     if (packageId == SYS_PACKAGE_ID && !mAliasId.empty() &&
7258             res >= mAliasId.front().first && res <= mAliasId.back().first) {
7259         const auto alias_it = std::lower_bound(mAliasId.begin(), mAliasId.end(), res,
7260                                                [](const AliasMap::value_type& pair,
7261                                                   uint32_t val) { return pair.first < val; });
7262         if (alias_it != mAliasId.end() && alias_it->first == res) {
7263             // Rewrite the resource id to its alias resource id. Since the alias resource id is a
7264             // compile-time id, it still needs to be resolved further.
7265             res = alias_it->second;
7266         }
7267     }
7268     if (packageId == SYS_PACKAGE_ID || (packageId == APP_PACKAGE_ID && !mAppAsLib)) {
7269         // No lookup needs to be done, app and framework package IDs are absolute.
7270         *resId = res;
7271         return NO_ERROR;
7272     }
7273 
7274     // Do a proper lookup.
7275     uint8_t translatedId = mLookupTable[packageId];
7276     if (translatedId == 0) {
7277         ALOGW("DynamicRefTable(0x%02x): No mapping for build-time package ID 0x%02x.",
7278                 (uint8_t)mAssignedPackageId, (uint8_t)packageId);
7279         for (size_t i = 0; i < 256; i++) {
7280             if (mLookupTable[i] != 0) {
7281                 ALOGW("e[0x%02x] -> 0x%02x", (uint8_t)i, mLookupTable[i]);
7282             }
7283         }
7284         return UNKNOWN_ERROR;
7285     }
7286 
7287     *resId = (res & 0x00ffffff) | (((uint32_t) translatedId) << 24);
7288     return NO_ERROR;
7289 }
7290 
requiresLookup(const Res_value * value) const7291 bool DynamicRefTable::requiresLookup(const Res_value* value) const {
7292     // Only resolve non-dynamic references and attributes if the package is loaded as a
7293     // library or if a shared library is attempting to retrieve its own resource
7294     if ((value->dataType == Res_value::TYPE_REFERENCE ||
7295          value->dataType == Res_value::TYPE_ATTRIBUTE) &&
7296         (mAppAsLib || (Res_GETPACKAGE(value->data) + 1) == 0)) {
7297         return true;
7298     }
7299     return value->dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE ||
7300            value->dataType == Res_value::TYPE_DYNAMIC_REFERENCE;
7301 }
7302 
lookupResourceValue(Res_value * value) const7303 status_t DynamicRefTable::lookupResourceValue(Res_value* value) const {
7304     if (!requiresLookup(value)) {
7305       return NO_ERROR;
7306     }
7307 
7308     uint8_t resolvedType = Res_value::TYPE_REFERENCE;
7309     switch (value->dataType) {
7310         case Res_value::TYPE_ATTRIBUTE:
7311             resolvedType = Res_value::TYPE_ATTRIBUTE;
7312             FALLTHROUGH_INTENDED;
7313         case Res_value::TYPE_REFERENCE:
7314         break;
7315         case Res_value::TYPE_DYNAMIC_ATTRIBUTE:
7316             resolvedType = Res_value::TYPE_ATTRIBUTE;
7317             FALLTHROUGH_INTENDED;
7318         case Res_value::TYPE_DYNAMIC_REFERENCE:
7319             break;
7320         default:
7321             return NO_ERROR;
7322     }
7323 
7324     status_t err = lookupResourceId(&value->data);
7325     if (err != NO_ERROR) {
7326         return err;
7327     }
7328 
7329     value->dataType = resolvedType;
7330     return NO_ERROR;
7331 }
7332 
7333 class IdmapMatchingResources;
7334 
7335 class IdmapTypeMapping {
7336 public:
add(uint32_t targetResId,uint32_t overlayResId)7337     void add(uint32_t targetResId, uint32_t overlayResId) {
7338         uint8_t targetTypeId = Res_GETTYPE(targetResId);
7339         auto& entries = mData[targetTypeId];
7340         entries.insert(std::make_pair(targetResId, overlayResId));
7341     }
7342 
empty() const7343     bool empty() const {
7344         return mData.empty();
7345     }
7346 
7347 private:
7348     // resource type ID in context of target -> set of resource entries mapping target -> overlay
7349     std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>> mData;
7350 
7351     friend IdmapMatchingResources;
7352 };
7353 
7354 class IdmapMatchingResources {
7355 public:
IdmapMatchingResources(std::unique_ptr<IdmapTypeMapping> tm)7356     IdmapMatchingResources(std::unique_ptr<IdmapTypeMapping> tm) : mTypeMapping(std::move(tm)) {
7357         assert(mTypeMapping);
7358         for (auto ti = mTypeMapping->mData.cbegin(); ti != mTypeMapping->mData.cend(); ++ti) {
7359             uint32_t lastSeen = 0xffffffff;
7360             size_t totalEntries = 0;
7361             for (auto ei = ti->second.cbegin(); ei != ti->second.cend(); ++ei) {
7362                 assert(lastSeen == 0xffffffff || lastSeen < ei->first);
7363                 mEntryPadding[ei->first] = (lastSeen == 0xffffffff) ? 0 : ei->first - lastSeen - 1;
7364                 lastSeen = ei->first;
7365                 totalEntries += 1 + mEntryPadding[ei->first];
7366             }
7367             mNumberOfEntriesIncludingPadding[ti->first] = totalEntries;
7368         }
7369     }
7370 
getTypeMapping() const7371     const std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>>& getTypeMapping() const {
7372         return mTypeMapping->mData;
7373     }
7374 
getNumberOfEntriesIncludingPadding(uint8_t type) const7375     size_t getNumberOfEntriesIncludingPadding(uint8_t type) const {
7376         return mNumberOfEntriesIncludingPadding.at(type);
7377     }
7378 
getPadding(uint32_t resid) const7379     size_t getPadding(uint32_t resid) const {
7380         return mEntryPadding.at(resid);
7381     }
7382 
7383 private:
7384     // resource type ID in context of target -> set of resource entries mapping target -> overlay
7385     const std::unique_ptr<IdmapTypeMapping> mTypeMapping;
7386 
7387     // resource ID in context of target -> trailing padding for that resource (call FixPadding
7388     // before use)
7389     std::map<uint32_t, size_t> mEntryPadding;
7390 
7391     // resource type ID in context of target -> total number of entries, including padding entries,
7392     // for that type (call FixPadding before use)
7393     std::map<uint8_t, size_t> mNumberOfEntriesIncludingPadding;
7394 };
7395 
createIdmap(const ResTable & targetResTable,uint32_t targetCrc,uint32_t overlayCrc,const char * targetPath,const char * overlayPath,void ** outData,size_t * outSize) const7396 status_t ResTable::createIdmap(const ResTable& targetResTable,
7397         uint32_t targetCrc, uint32_t overlayCrc,
7398         const char* targetPath, const char* overlayPath,
7399         void** outData, size_t* outSize) const
7400 {
7401     if (targetPath == NULL || overlayPath == NULL || outData == NULL || outSize == NULL) {
7402         ALOGE("idmap: unexpected NULL parameter");
7403         return UNKNOWN_ERROR;
7404     }
7405     if (strlen(targetPath) > 255) {
7406         ALOGE("idmap: target path exceeds idmap file format limit of 255 chars");
7407         return UNKNOWN_ERROR;
7408     }
7409     if (strlen(overlayPath) > 255) {
7410         ALOGE("idmap: overlay path exceeds idmap file format limit of 255 chars");
7411         return UNKNOWN_ERROR;
7412     }
7413     if (mPackageGroups.size() == 0 || mPackageGroups[0]->packages.size() == 0) {
7414         ALOGE("idmap: invalid overlay package");
7415         return UNKNOWN_ERROR;
7416     }
7417     if (targetResTable.mPackageGroups.size() == 0 ||
7418             targetResTable.mPackageGroups[0]->packages.size() == 0) {
7419         ALOGE("idmap: invalid target package");
7420         return UNKNOWN_ERROR;
7421     }
7422 
7423     // Idmap is not aware of overlayable, exit since policy checks can't be done
7424     if (targetResTable.mPackageGroups[0]->packages[0]->definesOverlayable) {
7425         return UNKNOWN_ERROR;
7426     }
7427 
7428     const ResTable_package* targetPackageStruct =
7429         targetResTable.mPackageGroups[0]->packages[0]->package;
7430     const size_t tmpNameSize = arraysize(targetPackageStruct->name);
7431     char16_t tmpName[tmpNameSize];
7432     strcpy16_dtoh(tmpName, targetPackageStruct->name, tmpNameSize);
7433     const String16 targetPackageName(tmpName);
7434 
7435     const PackageGroup* packageGroup = mPackageGroups[0];
7436 
7437     // find the resources that exist in both packages
7438     auto typeMapping = std::make_unique<IdmapTypeMapping>();
7439     for (size_t typeIndex = 0; typeIndex < packageGroup->types.size(); ++typeIndex) {
7440         const TypeList& typeList = packageGroup->types[typeIndex];
7441         if (typeList.isEmpty()) {
7442             continue;
7443         }
7444         const Type* typeConfigs = typeList[0];
7445 
7446         for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
7447             uint32_t overlay_resid = Res_MAKEID(packageGroup->id - 1, typeIndex, entryIndex);
7448             resource_name current_res;
7449             if (!getResourceName(overlay_resid, false, &current_res)) {
7450                 continue;
7451             }
7452 
7453             uint32_t typeSpecFlags = 0u;
7454             const uint32_t target_resid = targetResTable.identifierForName(
7455                     current_res.name,
7456                     current_res.nameLen,
7457                     current_res.type,
7458                     current_res.typeLen,
7459                     targetPackageName.c_str(),
7460                     targetPackageName.size(),
7461                     &typeSpecFlags);
7462 
7463             if (target_resid == 0) {
7464                 continue;
7465             }
7466 
7467             typeMapping->add(target_resid, overlay_resid);
7468         }
7469     }
7470 
7471     if (typeMapping->empty()) {
7472         ALOGE("idmap: no matching resources");
7473         return UNKNOWN_ERROR;
7474     }
7475 
7476     const IdmapMatchingResources matchingResources(std::move(typeMapping));
7477 
7478     // write idmap
7479     *outSize = ResTable::IDMAP_HEADER_SIZE_BYTES; // magic, version, target and overlay crc
7480     *outSize += 2 * sizeof(uint16_t); // target package id, type count
7481     auto fixedTypeMapping = matchingResources.getTypeMapping();
7482     const auto typesEnd = fixedTypeMapping.cend();
7483     for (auto ti = fixedTypeMapping.cbegin(); ti != typesEnd; ++ti) {
7484         *outSize += 4 * sizeof(uint16_t); // target type, overlay type, entry count, entry offset
7485         *outSize += matchingResources.getNumberOfEntriesIncludingPadding(ti->first) *
7486             sizeof(uint32_t); // entries
7487     }
7488     if ((*outData = malloc(*outSize)) == NULL) {
7489         return NO_MEMORY;
7490     }
7491 
7492     // write idmap header
7493     uint32_t* data = reinterpret_cast<uint32_t*>(*outData);
7494     *data++ = htodl(IDMAP_MAGIC); // write: magic
7495     *data++ = htodl(ResTable::IDMAP_CURRENT_VERSION); // write: version
7496     *data++ = htodl(targetCrc); // write: target crc
7497     *data++ = htodl(overlayCrc); // write: overlay crc
7498 
7499     char* charData = reinterpret_cast<char*>(data);
7500     size_t pathLen = strlen(targetPath);
7501     for (size_t i = 0; i < 256; ++i) {
7502         *charData++ = i < pathLen ? targetPath[i] : '\0'; // write: target path
7503     }
7504     pathLen = strlen(overlayPath);
7505     for (size_t i = 0; i < 256; ++i) {
7506         *charData++ = i < pathLen ? overlayPath[i] : '\0'; // write: overlay path
7507     }
7508     data += (2 * 256) / sizeof(uint32_t);
7509 
7510     // write idmap data header
7511     uint16_t* typeData = reinterpret_cast<uint16_t*>(data);
7512     *typeData++ = htods(targetPackageStruct->id); // write: target package id
7513     *typeData++ =
7514         htods(static_cast<uint16_t>(fixedTypeMapping.size())); // write: type count
7515 
7516     // write idmap data
7517     for (auto ti = fixedTypeMapping.cbegin(); ti != typesEnd; ++ti) {
7518         const size_t entryCount = matchingResources.getNumberOfEntriesIncludingPadding(ti->first);
7519         auto ei = ti->second.cbegin();
7520         *typeData++ = htods(Res_GETTYPE(ei->first) + 1); // write: target type id
7521         *typeData++ = htods(Res_GETTYPE(ei->second) + 1); // write: overlay type id
7522         *typeData++ = htods(entryCount); // write: entry count
7523         *typeData++ = htods(Res_GETENTRY(ei->first)); // write: (target) entry offset
7524         uint32_t *entryData = reinterpret_cast<uint32_t*>(typeData);
7525         for (; ei != ti->second.cend(); ++ei) {
7526             const size_t padding = matchingResources.getPadding(ei->first);
7527             for (size_t i = 0; i < padding; ++i) {
7528                 *entryData++ = htodl(0xffffffff); // write: padding
7529             }
7530             *entryData++ = htodl(Res_GETENTRY(ei->second)); // write: (overlay) entry
7531         }
7532         typeData += entryCount * 2;
7533     }
7534 
7535     return NO_ERROR;
7536 }
7537 
getIdmapInfo(const void * idmap,size_t sizeBytes,uint32_t * pVersion,uint32_t * pTargetCrc,uint32_t * pOverlayCrc,String8 * pTargetPath,String8 * pOverlayPath)7538 bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes,
7539                             uint32_t* pVersion,
7540                             uint32_t* pTargetCrc, uint32_t* pOverlayCrc,
7541                             String8* pTargetPath, String8* pOverlayPath)
7542 {
7543     const uint32_t* map = (const uint32_t*)idmap;
7544     if (!assertIdmapHeader(map, sizeBytes)) {
7545         return false;
7546     }
7547     if (pVersion) {
7548         *pVersion = dtohl(map[1]);
7549     }
7550     if (pTargetCrc) {
7551         *pTargetCrc = dtohl(map[2]);
7552     }
7553     if (pOverlayCrc) {
7554         *pOverlayCrc = dtohl(map[3]);
7555     }
7556     if (pTargetPath) {
7557         *pTargetPath = reinterpret_cast<const char*>(map + 4);
7558     }
7559     if (pOverlayPath) {
7560         *pOverlayPath = reinterpret_cast<const char*>(map + 4 + 256 / sizeof(uint32_t));
7561     }
7562     return true;
7563 }
7564 
7565 
7566 #define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).c_str())
7567 
7568 #define CHAR16_ARRAY_EQ(constant, var, len) \
7569         (((len) == (sizeof(constant)/sizeof((constant)[0]))) && (0 == memcmp((var), (constant), (len))))
7570 
print_complex(uint32_t complex,bool isFraction)7571 static void print_complex(uint32_t complex, bool isFraction)
7572 {
7573     const float MANTISSA_MULT =
7574         1.0f / (1<<Res_value::COMPLEX_MANTISSA_SHIFT);
7575     const float RADIX_MULTS[] = {
7576         1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
7577         1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
7578     };
7579 
7580     float value = (complex&(Res_value::COMPLEX_MANTISSA_MASK
7581                    <<Res_value::COMPLEX_MANTISSA_SHIFT))
7582             * RADIX_MULTS[(complex>>Res_value::COMPLEX_RADIX_SHIFT)
7583                             & Res_value::COMPLEX_RADIX_MASK];
7584     printf("%f", value);
7585 
7586     if (!isFraction) {
7587         switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
7588             case Res_value::COMPLEX_UNIT_PX: printf("px"); break;
7589             case Res_value::COMPLEX_UNIT_DIP: printf("dp"); break;
7590             case Res_value::COMPLEX_UNIT_SP: printf("sp"); break;
7591             case Res_value::COMPLEX_UNIT_PT: printf("pt"); break;
7592             case Res_value::COMPLEX_UNIT_IN: printf("in"); break;
7593             case Res_value::COMPLEX_UNIT_MM: printf("mm"); break;
7594             default: printf(" (unknown unit)"); break;
7595         }
7596     } else {
7597         switch ((complex>>Res_value::COMPLEX_UNIT_SHIFT)&Res_value::COMPLEX_UNIT_MASK) {
7598             case Res_value::COMPLEX_UNIT_FRACTION: printf("%%"); break;
7599             case Res_value::COMPLEX_UNIT_FRACTION_PARENT: printf("%%p"); break;
7600             default: printf(" (unknown unit)"); break;
7601         }
7602     }
7603 }
7604 
7605 // Normalize a string for output
normalizeForOutput(const char * input)7606 String8 ResTable::normalizeForOutput( const char *input )
7607 {
7608     String8 ret;
7609     char buff[2];
7610     buff[1] = '\0';
7611 
7612     while (*input != '\0') {
7613         switch (*input) {
7614             // All interesting characters are in the ASCII zone, so we are making our own lives
7615             // easier by scanning the string one byte at a time.
7616         case '\\':
7617             ret += "\\\\";
7618             break;
7619         case '\n':
7620             ret += "\\n";
7621             break;
7622         case '"':
7623             ret += "\\\"";
7624             break;
7625         default:
7626             buff[0] = *input;
7627             ret += buff;
7628             break;
7629         }
7630 
7631         input++;
7632     }
7633 
7634     return ret;
7635 }
7636 
print_value(const Package * pkg,const Res_value & value) const7637 void ResTable::print_value(const Package* pkg, const Res_value& value) const
7638 {
7639     if (value.dataType == Res_value::TYPE_NULL) {
7640         if (value.data == Res_value::DATA_NULL_UNDEFINED) {
7641             printf("(null)\n");
7642         } else if (value.data == Res_value::DATA_NULL_EMPTY) {
7643             printf("(null empty)\n");
7644         } else {
7645             // This should never happen.
7646             printf("(null) 0x%08x\n", value.data);
7647         }
7648     } else if (value.dataType == Res_value::TYPE_REFERENCE) {
7649         printf("(reference) 0x%08x\n", value.data);
7650     } else if (value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE) {
7651         printf("(dynamic reference) 0x%08x\n", value.data);
7652     } else if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
7653         printf("(attribute) 0x%08x\n", value.data);
7654     } else if (value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE) {
7655         printf("(dynamic attribute) 0x%08x\n", value.data);
7656     } else if (value.dataType == Res_value::TYPE_STRING) {
7657         size_t len;
7658         const char* str8 = UnpackOptionalString(pkg->header->values.string8At(
7659                 value.data), &len);
7660         if (str8 != NULL) {
7661             printf("(string8) \"%s\"\n", normalizeForOutput(str8).c_str());
7662         } else {
7663             const char16_t* str16 = UnpackOptionalString(pkg->header->values.stringAt(
7664                     value.data), &len);
7665             if (str16 != NULL) {
7666                 printf("(string16) \"%s\"\n",
7667                     normalizeForOutput(String8(str16, len).c_str()).c_str());
7668             } else {
7669                 printf("(string) null\n");
7670             }
7671         }
7672     } else if (value.dataType == Res_value::TYPE_FLOAT) {
7673         printf("(float) %g\n", *(const float*)&value.data);
7674     } else if (value.dataType == Res_value::TYPE_DIMENSION) {
7675         printf("(dimension) ");
7676         print_complex(value.data, false);
7677         printf("\n");
7678     } else if (value.dataType == Res_value::TYPE_FRACTION) {
7679         printf("(fraction) ");
7680         print_complex(value.data, true);
7681         printf("\n");
7682     } else if (value.dataType >= Res_value::TYPE_FIRST_COLOR_INT
7683             && value.dataType <= Res_value::TYPE_LAST_COLOR_INT) {
7684         printf("(color) #%08x\n", value.data);
7685     } else if (value.dataType == Res_value::TYPE_INT_BOOLEAN) {
7686         printf("(boolean) %s\n", value.data ? "true" : "false");
7687     } else if (value.dataType >= Res_value::TYPE_FIRST_INT
7688             && value.dataType <= Res_value::TYPE_LAST_INT) {
7689         printf("(int) 0x%08x or %d\n", value.data, value.data);
7690     } else {
7691         printf("(unknown type) t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)\n",
7692                (int)value.dataType, (int)value.data,
7693                (int)value.size, (int)value.res0);
7694     }
7695 }
7696 
print(bool inclValues) const7697 void ResTable::print(bool inclValues) const
7698 {
7699     if (mError != 0) {
7700         printf("mError=0x%x (%s)\n", mError, strerror(mError));
7701     }
7702     size_t pgCount = mPackageGroups.size();
7703     printf("Package Groups (%d)\n", (int)pgCount);
7704     for (size_t pgIndex=0; pgIndex<pgCount; pgIndex++) {
7705         const PackageGroup* pg = mPackageGroups[pgIndex];
7706         printf("Package Group %d id=0x%02x packageCount=%d name=%s\n",
7707                 (int)pgIndex, pg->id, (int)pg->packages.size(),
7708                 String8(pg->name).c_str());
7709 
7710         const KeyedVector<String16, uint8_t>& refEntries = pg->dynamicRefTable.entries();
7711         const size_t refEntryCount = refEntries.size();
7712         if (refEntryCount > 0) {
7713             printf("  DynamicRefTable entryCount=%d:\n", (int) refEntryCount);
7714             for (size_t refIndex = 0; refIndex < refEntryCount; refIndex++) {
7715                 printf("    0x%02x -> %s\n",
7716                         refEntries.valueAt(refIndex),
7717                         String8(refEntries.keyAt(refIndex)).c_str());
7718             }
7719             printf("\n");
7720         }
7721 
7722         // Determine the number of resource splits for the resource types in this package.
7723         // It needs to be done outside of the loop below so all of the information for a
7724         // is displayed in a single block. Otherwise, a resource split's resource types
7725         // would be interleaved with other splits.
7726         size_t splitCount = 0;
7727         for (size_t typeIndex = 0; typeIndex < pg->types.size(); typeIndex++) {
7728             splitCount = max(splitCount, pg->types[typeIndex].size());
7729         }
7730 
7731         int packageId = pg->id;
7732         for (size_t splitIndex = 0; splitIndex < splitCount; splitIndex++) {
7733             size_t pkgCount = pg->packages.size();
7734             for (size_t pkgIndex=0; pkgIndex<pkgCount; pkgIndex++) {
7735                 const Package* pkg = pg->packages[pkgIndex];
7736                 // Use a package's real ID, since the ID may have been assigned
7737                 // if this package is a shared library.
7738                 packageId = pkg->package->id;
7739                 char16_t tmpName[sizeof(pkg->package->name)/sizeof(pkg->package->name[0])];
7740                 strcpy16_dtoh(tmpName, pkg->package->name,
7741                               sizeof(pkg->package->name)/sizeof(pkg->package->name[0]));
7742                 printf("  Package %d id=0x%02x name=%s\n", (int)pkgIndex,
7743                         pkg->package->id, String8(tmpName).c_str());
7744             }
7745 
7746             for (size_t typeIndex = 0; typeIndex < pg->types.size(); typeIndex++) {
7747                 const TypeList& typeList = pg->types[typeIndex];
7748                 if (splitIndex >= typeList.size() || typeList.isEmpty()) {
7749                     // Only dump if the split exists and contains entries for this type
7750                     continue;
7751                 }
7752                 const Type* typeConfigs = typeList[splitIndex];
7753                 const size_t NTC = typeConfigs->configs.size();
7754                 printf("    type %d configCount=%d entryCount=%d\n",
7755                        (int)typeIndex, (int)NTC, (int)typeConfigs->entryCount);
7756                 if (typeConfigs->typeSpecFlags != NULL) {
7757                     for (size_t entryIndex=0; entryIndex<typeConfigs->entryCount; entryIndex++) {
7758                         uint32_t resID = (0xff000000 & ((packageId)<<24))
7759                                     | (0x00ff0000 & ((typeIndex+1)<<16))
7760                                     | (0x0000ffff & (entryIndex));
7761                         // Since we are creating resID without actually
7762                         // iterating over them, we have no idea which is a
7763                         // dynamic reference. We must check.
7764                         if (packageId == 0) {
7765                             pg->dynamicRefTable.lookupResourceId(&resID);
7766                         }
7767 
7768                         resource_name resName;
7769                         if (this->getResourceName(resID, true, &resName)) {
7770                             String8 type8;
7771                             String8 name8;
7772                             if (resName.type8 != NULL) {
7773                                 type8 = String8(resName.type8, resName.typeLen);
7774                             } else {
7775                                 type8 = String8(resName.type, resName.typeLen);
7776                             }
7777                             if (resName.name8 != NULL) {
7778                                 name8 = String8(resName.name8, resName.nameLen);
7779                             } else {
7780                                 name8 = String8(resName.name, resName.nameLen);
7781                             }
7782                             printf("      spec resource 0x%08x %s:%s/%s: flags=0x%08x\n",
7783                                 resID,
7784                                 CHAR16_TO_CSTR(resName.package, resName.packageLen),
7785                                 type8.c_str(), name8.c_str(),
7786                                 dtohl(typeConfigs->typeSpecFlags[entryIndex]));
7787                         } else {
7788                             printf("      INVALID TYPE CONFIG FOR RESOURCE 0x%08x\n", resID);
7789                         }
7790                     }
7791                 }
7792                 for (size_t configIndex=0; configIndex<NTC; configIndex++) {
7793                     const ResTable_type* type = typeConfigs->configs[configIndex];
7794                     if ((((uint64_t)type)&0x3) != 0) {
7795                         printf("      NON-INTEGER ResTable_type ADDRESS: %p\n", type);
7796                         continue;
7797                     }
7798 
7799                     // Always copy the config, as fields get added and we need to
7800                     // set the defaults.
7801                     ResTable_config thisConfig;
7802                     thisConfig.copyFromDtoH(type->config);
7803 
7804                     String8 configStr = thisConfig.toString();
7805                     printf("      config %s", configStr.size() > 0
7806                             ? configStr.c_str() : "(default)");
7807                     if (type->flags != 0u) {
7808                         printf(" flags=0x%02x", type->flags);
7809                         if (type->flags & ResTable_type::FLAG_SPARSE) {
7810                             printf(" [sparse]");
7811                         }
7812                         if (type->flags & ResTable_type::FLAG_OFFSET16) {
7813                             printf(" [offset16]");
7814                         }
7815                     }
7816 
7817                     printf(":\n");
7818 
7819                     size_t entryCount = dtohl(type->entryCount);
7820                     uint32_t entriesStart = dtohl(type->entriesStart);
7821                     if ((entriesStart&0x3) != 0) {
7822                         printf("      NON-INTEGER ResTable_type entriesStart OFFSET: 0x%x\n",
7823                                entriesStart);
7824                         continue;
7825                     }
7826                     uint32_t typeSize = dtohl(type->header.size);
7827                     if ((typeSize&0x3) != 0) {
7828                         printf("      NON-INTEGER ResTable_type header.size: 0x%x\n", typeSize);
7829                         continue;
7830                     }
7831 
7832                     const uint32_t* const eindex = (const uint32_t*)
7833                             (((const uint8_t*)type) + dtohs(type->header.headerSize));
7834                     for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
7835                         size_t entryId;
7836                         uint32_t thisOffset;
7837                         if (type->flags & ResTable_type::FLAG_SPARSE) {
7838                             const ResTable_sparseTypeEntry* entry =
7839                                     reinterpret_cast<const ResTable_sparseTypeEntry*>(
7840                                             eindex + entryIndex);
7841                             entryId = dtohs(entry->idx);
7842                             // Offsets are encoded as divided by 4.
7843                             thisOffset = static_cast<uint32_t>(dtohs(entry->offset)) * 4u;
7844                         } else {
7845                             entryId = entryIndex;
7846                             if (type->flags & ResTable_type::FLAG_OFFSET16) {
7847                                 const auto eindex16 =
7848                                     reinterpret_cast<const uint16_t*>(eindex);
7849                                 thisOffset = offset_from16(eindex16[entryIndex]);
7850                             } else {
7851                                 thisOffset = dtohl(eindex[entryIndex]);
7852                             }
7853                             if (thisOffset == ResTable_type::NO_ENTRY) {
7854                                 continue;
7855                             }
7856                         }
7857 
7858                         uint32_t resID = (0xff000000 & ((packageId)<<24))
7859                                     | (0x00ff0000 & ((typeIndex+1)<<16))
7860                                     | (0x0000ffff & (entryId));
7861                         if (packageId == 0) {
7862                             pg->dynamicRefTable.lookupResourceId(&resID);
7863                         }
7864                         resource_name resName;
7865                         if (this->getResourceName(resID, true, &resName)) {
7866                             String8 type8;
7867                             String8 name8;
7868                             if (resName.type8 != NULL) {
7869                                 type8 = String8(resName.type8, resName.typeLen);
7870                             } else {
7871                                 type8 = String8(resName.type, resName.typeLen);
7872                             }
7873                             if (resName.name8 != NULL) {
7874                                 name8 = String8(resName.name8, resName.nameLen);
7875                             } else {
7876                                 name8 = String8(resName.name, resName.nameLen);
7877                             }
7878                             printf("        resource 0x%08x %s:%s/%s: ", resID,
7879                                     CHAR16_TO_CSTR(resName.package, resName.packageLen),
7880                                     type8.c_str(), name8.c_str());
7881                         } else {
7882                             printf("        INVALID RESOURCE 0x%08x: ", resID);
7883                         }
7884                         if ((thisOffset&0x3) != 0) {
7885                             printf("NON-INTEGER OFFSET: 0x%x\n", thisOffset);
7886                             continue;
7887                         }
7888                         if ((thisOffset+sizeof(ResTable_entry)) > typeSize) {
7889                             printf("OFFSET OUT OF BOUNDS: 0x%x+0x%x (size is 0x%x)\n",
7890                                    entriesStart, thisOffset, typeSize);
7891                             continue;
7892                         }
7893 
7894                         const ResTable_entry* ent = (const ResTable_entry*)
7895                             (((const uint8_t*)type) + entriesStart + thisOffset);
7896                         if (((entriesStart + thisOffset)&0x3) != 0) {
7897                             printf("NON-INTEGER ResTable_entry OFFSET: 0x%x\n",
7898                                  (entriesStart + thisOffset));
7899                             continue;
7900                         }
7901 
7902                         uintptr_t esize = ent->size();
7903                         if ((esize&0x3) != 0) {
7904                             printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void *)esize);
7905                             continue;
7906                         }
7907                         if ((thisOffset+esize) > typeSize) {
7908                             printf("ResTable_entry OUT OF BOUNDS: 0x%x+0x%x+%p (size is 0x%x)\n",
7909                                    entriesStart, thisOffset, (void *)esize, typeSize);
7910                             continue;
7911                         }
7912 
7913                         const Res_value* valuePtr = NULL;
7914                         const ResTable_map_entry* bagPtr = ent->map_entry();
7915                         Res_value value;
7916                         if (bagPtr) {
7917                             printf("<bag>");
7918                         } else {
7919                             value = ent->value();
7920                             printf("t=0x%02x d=0x%08x (s=0x%04x r=0x%02x)",
7921                                    (int)value.dataType, (int)value.data,
7922                                    (int)value.size, (int)value.res0);
7923                         }
7924 
7925                         if (ent->flags() & ResTable_entry::FLAG_PUBLIC) {
7926                             printf(" (PUBLIC)");
7927                         }
7928                         printf("\n");
7929 
7930                         if (inclValues) {
7931                             if (bagPtr == NULL) {
7932                                 printf("          ");
7933                                 print_value(typeConfigs->package, value);
7934                             } else {
7935                                 const int N = dtohl(bagPtr->count);
7936                                 const uint8_t* baseMapPtr = (const uint8_t*)ent;
7937                                 size_t mapOffset = esize;
7938                                 const ResTable_map* mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
7939                                 const uint32_t parent = dtohl(bagPtr->parent.ident);
7940                                 uint32_t resolvedParent = parent;
7941                                 if (Res_GETPACKAGE(resolvedParent) + 1 == 0) {
7942                                     status_t err =
7943                                         pg->dynamicRefTable.lookupResourceId(&resolvedParent);
7944                                     if (err != NO_ERROR) {
7945                                         resolvedParent = 0;
7946                                     }
7947                                 }
7948                                 printf("          Parent=0x%08x(Resolved=0x%08x), Count=%d\n",
7949                                         parent, resolvedParent, N);
7950                                 for (int i=0;
7951                                      i<N && mapOffset < (typeSize-sizeof(ResTable_map)); i++) {
7952                                     printf("          #%i (Key=0x%08x): ",
7953                                         i, dtohl(mapPtr->name.ident));
7954                                     value.copyFrom_dtoh(mapPtr->value);
7955                                     print_value(typeConfigs->package, value);
7956                                     const size_t size = dtohs(mapPtr->value.size);
7957                                     mapOffset += size + sizeof(*mapPtr)-sizeof(mapPtr->value);
7958                                     mapPtr = (ResTable_map*)(baseMapPtr+mapOffset);
7959                                 }
7960                             }
7961                         }
7962                     }
7963                 }
7964             }
7965         }
7966     }
7967 }
7968 
7969 }   // namespace android
7970