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