Home | History | Annotate | Download | only in Renderscript
      1 /*
      2  * Copyright 2012, 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 //===----------------------------------------------------------------------===//
     18 // This file implements RSInfo::ReadFromFile()
     19 //===----------------------------------------------------------------------===//
     20 
     21 #include "bcc/Renderscript/RSInfo.h"
     22 
     23 #include <new>
     24 
     25 #include <utils/FileMap.h>
     26 
     27 #include "bcc/Support/Log.h"
     28 #include "bcc/Support/InputFile.h"
     29 
     30 using namespace bcc;
     31 
     32 namespace {
     33 
     34 template<typename ItemType, typename ItemContainer>
     35 inline bool helper_read_list_item(const ItemType &pItem,
     36                                   const RSInfo &pInfo,
     37                                   ItemContainer &pResult);
     38 
     39 // Process PragmaItem in the file
     40 template<> inline bool
     41 helper_read_list_item<rsinfo::PragmaItem, RSInfo::PragmaListTy>(
     42     const rsinfo::PragmaItem &pItem,
     43     const RSInfo &pInfo,
     44     RSInfo::PragmaListTy &pResult)
     45 {
     46   const char *key = pInfo.getStringFromPool(pItem.key);
     47   const char *value =pInfo.getStringFromPool(pItem.value);
     48 
     49   if (key == NULL) {
     50     ALOGE("Invalid string index %d for key in RS pragma list.", pItem.key);
     51     return false;
     52   }
     53 
     54   if (value == NULL) {
     55     ALOGE("Invalid string index %d for value in RS pragma list.", pItem.value);
     56     return false;
     57   }
     58 
     59   pResult.push(std::make_pair(key, value));
     60   return true;
     61 }
     62 
     63 // Procee ObjectSlotItem in the file
     64 template<> inline bool
     65 helper_read_list_item<rsinfo::ObjectSlotItem, RSInfo::ObjectSlotListTy>(
     66     const rsinfo::ObjectSlotItem &pItem,
     67     const RSInfo &pInfo,
     68     RSInfo::ObjectSlotListTy &pResult)
     69 {
     70   pResult.push(pItem.slot);
     71   return true;
     72 }
     73 
     74 // Procee ExportVarNameItem in the file
     75 template<> inline bool
     76 helper_read_list_item<rsinfo::ExportVarNameItem, RSInfo::ExportVarNameListTy>(
     77     const rsinfo::ExportVarNameItem &pItem,
     78     const RSInfo &pInfo,
     79     RSInfo::ExportVarNameListTy &pResult)
     80 {
     81   const char *name = pInfo.getStringFromPool(pItem.name);
     82 
     83   if (name == NULL) {
     84     ALOGE("Invalid string index %d for name in RS export vars.", pItem.name);
     85     return false;
     86   }
     87 
     88   pResult.push(name);
     89   return true;
     90 }
     91 
     92 // Procee ExportFuncNameItem in the file
     93 template<> inline bool
     94 helper_read_list_item<rsinfo::ExportFuncNameItem, RSInfo::ExportFuncNameListTy>(
     95     const rsinfo::ExportFuncNameItem &pItem,
     96     const RSInfo &pInfo,
     97     RSInfo::ExportFuncNameListTy &pResult)
     98 {
     99   const char *name = pInfo.getStringFromPool(pItem.name);
    100 
    101   if (name == NULL) {
    102     ALOGE("Invalid string index %d for name in RS export funcs.", pItem.name);
    103     return false;
    104   }
    105 
    106   pResult.push(name);
    107   return true;
    108 }
    109 
    110 // Procee ExportForeachFuncItem in the file
    111 template<> inline bool
    112 helper_read_list_item<rsinfo::ExportForeachFuncItem, RSInfo::ExportForeachFuncListTy>(
    113     const rsinfo::ExportForeachFuncItem &pItem,
    114     const RSInfo &pInfo,
    115     RSInfo::ExportForeachFuncListTy &pResult)
    116 {
    117   const char *name = pInfo.getStringFromPool(pItem.name);
    118 
    119   if (name == NULL) {
    120     ALOGE("Invalid string index %d for name in RS export foreachs.", pItem.name);
    121     return false;
    122   }
    123 
    124   pResult.push(std::make_pair(name, pItem.signature));
    125   return true;
    126 }
    127 
    128 template<typename ItemType, typename ItemContainer>
    129 inline bool helper_read_list(const uint8_t *pData,
    130                              const RSInfo &pInfo,
    131                              const rsinfo::ListHeader &pHeader,
    132                              ItemContainer &pResult) {
    133   const ItemType *item;
    134 
    135   // Out-of-range exception has been checked.
    136   for (uint32_t i = 0; i < pHeader.count; i++) {
    137     item = reinterpret_cast<const ItemType *>(pData +
    138                                               pHeader.offset +
    139                                               i * pHeader.itemSize);
    140     if (!helper_read_list_item<ItemType, ItemContainer>(*item, pInfo, pResult)) {
    141       return false;
    142     }
    143   }
    144   return true;
    145 }
    146 
    147 } // end anonymous namespace
    148 
    149 RSInfo *RSInfo::ReadFromFile(InputFile &pInput) {
    150   android::FileMap *map = NULL;
    151   RSInfo *result = NULL;
    152   const uint8_t *data;
    153   const rsinfo::Header *header;
    154   size_t filesize;
    155   const char *input_filename = pInput.getName().c_str();
    156   const off_t cur_input_offset = pInput.tell();
    157 
    158   if (pInput.hasError()) {
    159     ALOGE("Invalid RS info file %s! (%s)", input_filename,
    160                                            pInput.getErrorMessage().c_str());
    161     goto bail;
    162   }
    163 
    164   filesize = pInput.getSize();
    165   if (pInput.hasError()) {
    166     ALOGE("Failed to get the size of RS info file %s! (%s)",
    167           input_filename, pInput.getErrorMessage().c_str());
    168     goto bail;
    169   }
    170 
    171   // Create memory map for the file.
    172   map = pInput.createMap(/* pOffset */cur_input_offset,
    173                          /* pLength */filesize - cur_input_offset);
    174   if (map == NULL) {
    175     ALOGE("Failed to map RS info file %s to the memory! (%s)",
    176           input_filename, pInput.getErrorMessage().c_str());
    177     goto bail;
    178   }
    179 
    180   data = reinterpret_cast<const uint8_t *>(map->getDataPtr());
    181 
    182   // Header starts at the beginning of the file.
    183   header = reinterpret_cast<const rsinfo::Header *>(data);
    184 
    185   // Check the magic.
    186   if (::memcmp(header->magic, RSINFO_MAGIC, sizeof(header->magic)) != 0) {
    187     ALOGV("Wrong magic found in the RS info file %s. Treat it as a dirty "
    188           "cache.", input_filename);
    189     goto bail;
    190   }
    191 
    192   // Check the version.
    193   if (::memcmp(header->version,
    194                RSINFO_VERSION,
    195                sizeof(header->version)) != 0) {
    196     ALOGV("Mismatch the version of RS info file %s: (current) %s v.s. (file) "
    197           "%s. Treat it as as a dirty cache.", input_filename, RSINFO_VERSION,
    198           header->version);
    199     goto bail;
    200   }
    201 
    202   // Check the size.
    203   if ((header->headerSize != sizeof(rsinfo::Header)) ||
    204       (header->pragmaList.itemSize != sizeof(rsinfo::PragmaItem)) ||
    205       (header->objectSlotList.itemSize != sizeof(rsinfo::ObjectSlotItem)) ||
    206       (header->exportVarNameList.itemSize != sizeof(rsinfo::ExportVarNameItem)) ||
    207       (header->exportFuncNameList.itemSize != sizeof(rsinfo::ExportFuncNameItem)) ||
    208       (header->exportForeachFuncList.itemSize != sizeof(rsinfo::ExportForeachFuncItem))) {
    209     ALOGW("Corrupted RS info file %s! (unexpected size found)", input_filename);
    210     goto bail;
    211   }
    212 
    213   // Check the range.
    214 #define LIST_DATA_RANGE(_list_header) \
    215   ((_list_header).offset + (_list_header).count * (_list_header).itemSize)
    216   if (((header->headerSize + header->strPoolSize) > filesize) ||
    217       (LIST_DATA_RANGE(header->pragmaList) > filesize) ||
    218       (LIST_DATA_RANGE(header->objectSlotList) > filesize) ||
    219       (LIST_DATA_RANGE(header->exportVarNameList) > filesize) ||
    220       (LIST_DATA_RANGE(header->exportFuncNameList) > filesize) ||
    221       (LIST_DATA_RANGE(header->exportForeachFuncList) > filesize)) {
    222     ALOGW("Corrupted RS info file %s! (data out of the range)", input_filename);
    223     goto bail;
    224   }
    225 #undef LIST_DATA_RANGE
    226 
    227   // File seems ok, create result RSInfo object.
    228   result = new (std::nothrow) RSInfo(header->strPoolSize);
    229   if (result == NULL) {
    230     ALOGE("Out of memory when create RSInfo object for %s!", input_filename);
    231     goto bail;
    232   }
    233 
    234   // Make advice on our access pattern.
    235   map->advise(android::FileMap::SEQUENTIAL);
    236 
    237   // Copy the header.
    238   ::memcpy(&result->mHeader, header, sizeof(rsinfo::Header));
    239 
    240   if (header->strPoolSize > 0) {
    241     // Copy the string pool. The string pool is immediately after the header at
    242     // the offset header->headerSize.
    243     if (result->mStringPool == NULL) {
    244       ALOGE("Out of memory when allocate string pool for RS info file %s!",
    245             input_filename);
    246       goto bail;
    247     }
    248     ::memcpy(result->mStringPool, data + result->mHeader.headerSize,
    249              result->mHeader.strPoolSize);
    250   }
    251 
    252   // Populate all the data to the result object.
    253   result->mSourceHash =
    254               reinterpret_cast<const uint8_t*>(result->getStringFromPool(header->sourceSha1Idx));
    255   if (result->mSourceHash == NULL) {
    256       ALOGE("Invalid string index %d for SHA-1 checksum of source.", header->sourceSha1Idx);
    257       goto bail;
    258   }
    259 
    260   result->mCompileCommandLine = result->getStringFromPool(header->compileCommandLineIdx);
    261   if (result->mCompileCommandLine == NULL) {
    262       ALOGE("Invalid string index %d for compile command line.", header->compileCommandLineIdx);
    263       goto bail;
    264   }
    265 
    266   result->mBuildFingerprint = result->getStringFromPool(header->buildFingerprintIdx);
    267   if (result->mBuildFingerprint == NULL) {
    268       ALOGE("Invalid string index %d for build fingerprint.", header->buildFingerprintIdx);
    269       goto bail;
    270   }
    271 
    272   if (!helper_read_list<rsinfo::PragmaItem, PragmaListTy>
    273         (data, *result, header->pragmaList, result->mPragmas)) {
    274     goto bail;
    275   }
    276 
    277   if (!helper_read_list<rsinfo::ObjectSlotItem, ObjectSlotListTy>
    278         (data, *result, header->objectSlotList, result->mObjectSlots)) {
    279     goto bail;
    280   }
    281 
    282   if (!helper_read_list<rsinfo::ExportVarNameItem, ExportVarNameListTy>
    283         (data, *result, header->exportVarNameList, result->mExportVarNames)) {
    284     goto bail;
    285   }
    286 
    287   if (!helper_read_list<rsinfo::ExportFuncNameItem, ExportFuncNameListTy>
    288         (data, *result, header->exportFuncNameList, result->mExportFuncNames)) {
    289     goto bail;
    290   }
    291 
    292   if (!helper_read_list<rsinfo::ExportForeachFuncItem, ExportForeachFuncListTy>
    293         (data, *result, header->exportForeachFuncList, result->mExportForeachFuncs)) {
    294     goto bail;
    295   }
    296 
    297   // Clean up.
    298   map->release();
    299 
    300   return result;
    301 
    302 bail:
    303   if (map != NULL) {
    304     map->release();
    305   }
    306 
    307   delete result;
    308 
    309   return NULL;
    310 } // RSInfo::ReadFromFile
    311