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