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