| /* |
| * 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 |