/* * Copyright 2012, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //===----------------------------------------------------------------------===// // This file implements RSInfo::ReadFromFile() //===----------------------------------------------------------------------===// #include "bcc/Renderscript/RSInfo.h" #include <new> #include <utils/FileMap.h> #include "bcc/Support/Log.h" #include "bcc/Support/InputFile.h" using namespace bcc; namespace { template<typename ItemType, typename ItemContainer> inline bool helper_read_list_item(const ItemType &pItem, const RSInfo &pInfo, ItemContainer &pResult); // Process DependencyTableItem in the file template<> inline bool helper_read_list_item<rsinfo::DependencyTableItem, RSInfo::DependencyTableTy>( const rsinfo::DependencyTableItem &pItem, const RSInfo &pInfo, RSInfo::DependencyTableTy &pResult) { const char *id = pInfo.getStringFromPool(pItem.id); const uint8_t *sha1 = reinterpret_cast<const uint8_t *>(pInfo.getStringFromPool(pItem.sha1)); if (id == NULL) { ALOGE("Invalid string index %d for source id in RS dependenct table.", pItem.id); return false; } if (sha1 == NULL) { ALOGE("Invalid string index %d for SHA-1 checksum in RS dependenct table.", pItem.id); return false; } pResult.push(std::make_pair(id, sha1)); return true; } // Process PragmaItem in the file template<> inline bool helper_read_list_item<rsinfo::PragmaItem, RSInfo::PragmaListTy>( const rsinfo::PragmaItem &pItem, const RSInfo &pInfo, RSInfo::PragmaListTy &pResult) { const char *key = pInfo.getStringFromPool(pItem.key); const char *value =pInfo.getStringFromPool(pItem.value); if (key == NULL) { ALOGE("Invalid string index %d for key in RS pragma list.", pItem.key); return false; } if (value == NULL) { ALOGE("Invalid string index %d for value in RS pragma list.", pItem.value); return false; } pResult.push(std::make_pair(key, value)); return true; } // Procee ObjectSlotItem in the file template<> inline bool helper_read_list_item<rsinfo::ObjectSlotItem, RSInfo::ObjectSlotListTy>( const rsinfo::ObjectSlotItem &pItem, const RSInfo &pInfo, RSInfo::ObjectSlotListTy &pResult) { pResult.push(pItem.slot); return true; } // Procee ExportVarNameItem in the file template<> inline bool helper_read_list_item<rsinfo::ExportVarNameItem, RSInfo::ExportVarNameListTy>( const rsinfo::ExportVarNameItem &pItem, const RSInfo &pInfo, RSInfo::ExportVarNameListTy &pResult) { const char *name = pInfo.getStringFromPool(pItem.name); if (name == NULL) { ALOGE("Invalid string index %d for name in RS export vars.", pItem.name); return false; } pResult.push(name); return true; } // Procee ExportFuncNameItem in the file template<> inline bool helper_read_list_item<rsinfo::ExportFuncNameItem, RSInfo::ExportFuncNameListTy>( const rsinfo::ExportFuncNameItem &pItem, const RSInfo &pInfo, RSInfo::ExportFuncNameListTy &pResult) { const char *name = pInfo.getStringFromPool(pItem.name); if (name == NULL) { ALOGE("Invalid string index %d for name in RS export funcs.", pItem.name); return false; } pResult.push(name); return true; } // Procee ExportForeachFuncItem in the file template<> inline bool helper_read_list_item<rsinfo::ExportForeachFuncItem, RSInfo::ExportForeachFuncListTy>( const rsinfo::ExportForeachFuncItem &pItem, const RSInfo &pInfo, RSInfo::ExportForeachFuncListTy &pResult) { const char *name = pInfo.getStringFromPool(pItem.name); if (name == NULL) { ALOGE("Invalid string index %d for name in RS export foreachs.", pItem.name); return false; } pResult.push(std::make_pair(name, pItem.signature)); return true; } template<typename ItemType, typename ItemContainer> inline bool helper_read_list(const uint8_t *pData, const RSInfo &pInfo, const rsinfo::ListHeader &pHeader, ItemContainer &pResult) { const ItemType *item; // Out-of-range exception has been checked. for (uint32_t i = 0; i < pHeader.count; i++) { item = reinterpret_cast<const ItemType *>(pData + pHeader.offset + i * pHeader.itemSize); if (!helper_read_list_item<ItemType, ItemContainer>(*item, pInfo, pResult)) { return false; } } return true; } } // end anonymous namespace RSInfo *RSInfo::ReadFromFile(InputFile &pInput, const DependencyTableTy &pDeps) { android::FileMap *map = NULL; RSInfo *result = NULL; const uint8_t *data; const rsinfo::Header *header; size_t filesize; const char *input_filename = pInput.getName().c_str(); const off_t cur_input_offset = pInput.tell(); if (pInput.hasError()) { ALOGE("Invalid RS info file %s! (%s)", input_filename, pInput.getErrorMessage().c_str()); goto bail; } filesize = pInput.getSize(); if (pInput.hasError()) { ALOGE("Failed to get the size of RS info file %s! (%s)", input_filename, pInput.getErrorMessage().c_str()); goto bail; } // Create memory map for the file. map = pInput.createMap(/* pOffset */cur_input_offset, /* pLength */filesize - cur_input_offset); if (map == NULL) { ALOGE("Failed to map RS info file %s to the memory! (%s)", input_filename, pInput.getErrorMessage().c_str()); goto bail; } data = reinterpret_cast<const uint8_t *>(map->getDataPtr()); // Header starts at the beginning of the file. header = reinterpret_cast<const rsinfo::Header *>(data); // Check the magic. if (::memcmp(header->magic, RSINFO_MAGIC, sizeof(header->magic)) != 0) { ALOGV("Wrong magic found in the RS info file %s. Treat it as a dirty " "cache.", input_filename); goto bail; } // Check the version. if (::memcmp(header->version, RSINFO_VERSION, sizeof((header->version)) != 0)) { ALOGV("Mismatch the version of RS info file %s: (current) %s v.s. (file) " "%s. Treat it as as a dirty cache.", input_filename, RSINFO_VERSION, header->version); goto bail; } // Check the size. if ((header->headerSize != sizeof(rsinfo::Header)) || (header->dependencyTable.itemSize != sizeof(rsinfo::DependencyTableItem)) || (header->pragmaList.itemSize != sizeof(rsinfo::PragmaItem)) || (header->objectSlotList.itemSize != sizeof(rsinfo::ObjectSlotItem)) || (header->exportVarNameList.itemSize != sizeof(rsinfo::ExportVarNameItem)) || (header->exportFuncNameList.itemSize != sizeof(rsinfo::ExportFuncNameItem)) || (header->exportForeachFuncList.itemSize != sizeof(rsinfo::ExportForeachFuncItem))) { ALOGW("Corrupted RS info file %s! (unexpected size found)", input_filename); goto bail; } // Check the range. #define LIST_DATA_RANGE(_list_header) \ ((_list_header).offset + (_list_header).count * (_list_header).itemSize) if (((header->headerSize + header->strPoolSize) > filesize) || (LIST_DATA_RANGE(header->dependencyTable) > filesize) || (LIST_DATA_RANGE(header->pragmaList) > filesize) || (LIST_DATA_RANGE(header->objectSlotList) > filesize) || (LIST_DATA_RANGE(header->exportVarNameList) > filesize) || (LIST_DATA_RANGE(header->exportFuncNameList) > filesize) || (LIST_DATA_RANGE(header->exportForeachFuncList) > filesize)) { ALOGW("Corrupted RS info file %s! (data out of the range)", input_filename); goto bail; } #undef LIST_DATA_RANGE // File seems ok, create result RSInfo object. result = new (std::nothrow) RSInfo(header->strPoolSize); if (result == NULL) { ALOGE("Out of memory when create RSInfo object for %s!", input_filename); goto bail; } // Make advice on our access pattern. map->advise(android::FileMap::SEQUENTIAL); // Copy the header. ::memcpy(&result->mHeader, header, sizeof(rsinfo::Header)); if (header->strPoolSize > 0) { // Copy the string pool. The string pool is immediately after the header at // the offset header->headerSize. if (result->mStringPool == NULL) { ALOGE("Out of memory when allocate string pool for RS info file %s!", input_filename); goto bail; } ::memcpy(result->mStringPool, data + result->mHeader.headerSize, result->mHeader.strPoolSize); } // Populate all the data to the result object. if (!helper_read_list<rsinfo::DependencyTableItem, DependencyTableTy> (data, *result, header->dependencyTable, result->mDependencyTable)) { goto bail; } // Check dependency to see whether the cache is dirty or not. if (!CheckDependency(*result, pInput.getName().c_str(), pDeps)) { goto bail; } if (!helper_read_list<rsinfo::PragmaItem, PragmaListTy> (data, *result, header->pragmaList, result->mPragmas)) { goto bail; } if (!helper_read_list<rsinfo::ObjectSlotItem, ObjectSlotListTy> (data, *result, header->objectSlotList, result->mObjectSlots)) { goto bail; } if (!helper_read_list<rsinfo::ExportVarNameItem, ExportVarNameListTy> (data, *result, header->exportVarNameList, result->mExportVarNames)) { goto bail; } if (!helper_read_list<rsinfo::ExportFuncNameItem, ExportFuncNameListTy> (data, *result, header->exportFuncNameList, result->mExportFuncNames)) { goto bail; } if (!helper_read_list<rsinfo::ExportForeachFuncItem, ExportForeachFuncListTy> (data, *result, header->exportForeachFuncList, result->mExportForeachFuncs)) { goto bail; } // Clean up. map->release(); return result; bail: if (map != NULL) { map->release(); } delete result; return NULL; } // RSInfo::ReadFromFile