Zonr Chang | 255cbc8 | 2012-04-12 13:29:43 +0800 | [diff] [blame] | 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 | |
Zonr Chang | 80232dd | 2012-04-12 15:38:53 +0800 | [diff] [blame] | 21 | #include "bcc/RenderScript/RSInfo.h" |
Zonr Chang | 255cbc8 | 2012-04-12 13:29:43 +0800 | [diff] [blame] | 22 | |
| 23 | #include <new> |
| 24 | |
| 25 | #include <utils/FileMap.h> |
| 26 | |
Zonr Chang | b519fe3 | 2012-04-12 16:44:01 +0800 | [diff] [blame] | 27 | #include "bcc/Support/Log.h" |
Zonr Chang | 80232dd | 2012-04-12 15:38:53 +0800 | [diff] [blame] | 28 | #include "bcc/Support/InputFile.h" |
Zonr Chang | 255cbc8 | 2012-04-12 13:29:43 +0800 | [diff] [blame] | 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 | |
Stephen Hines | 7dfc4d8 | 2012-05-03 12:25:21 -0700 | [diff] [blame^] | 176 | RSInfo *RSInfo::ReadFromFile(InputFile &pInput, |
| 177 | const RSScript::SourceDependencyListTy &pDeps) { |
Zonr Chang | 255cbc8 | 2012-04-12 13:29:43 +0800 | [diff] [blame] | 178 | android::FileMap *map = NULL; |
| 179 | RSInfo *result = NULL; |
| 180 | const uint8_t *data; |
| 181 | const rsinfo::Header *header; |
| 182 | size_t filesize; |
| 183 | const char *input_filename = pInput.getName().c_str(); |
| 184 | const off_t cur_input_offset = pInput.tell(); |
| 185 | |
| 186 | if (pInput.hasError()) { |
| 187 | ALOGE("Invalid RS info file %s! (%s)", input_filename, |
| 188 | pInput.getErrorMessage().c_str()); |
| 189 | goto bail; |
| 190 | } |
| 191 | |
| 192 | filesize = pInput.getSize(); |
| 193 | if (pInput.hasError()) { |
| 194 | ALOGE("Failed to get the size of RS info file %s! (%s)", |
| 195 | input_filename, pInput.getErrorMessage().c_str()); |
| 196 | goto bail; |
| 197 | } |
| 198 | |
| 199 | // Create memory map for the file. |
| 200 | map = pInput.createMap(/* pOffset */cur_input_offset, |
| 201 | /* pLength */filesize - cur_input_offset); |
| 202 | if (map == NULL) { |
| 203 | ALOGE("Failed to map RS info file %s to the memory! (%s)", |
| 204 | input_filename, pInput.getErrorMessage().c_str()); |
| 205 | goto bail; |
| 206 | } |
| 207 | |
| 208 | data = reinterpret_cast<const uint8_t *>(map->getDataPtr()); |
| 209 | |
| 210 | // Header starts at the beginning of the file. |
| 211 | header = reinterpret_cast<const rsinfo::Header *>(data); |
| 212 | |
| 213 | // Check the magic. |
| 214 | if (::memcmp(header->magic, RSINFO_MAGIC, sizeof(header->magic)) != 0) { |
| 215 | ALOGV("Wrong magic found in the RS info file %s. Treat it as a dirty " |
| 216 | "cache.", input_filename); |
| 217 | goto bail; |
| 218 | } |
| 219 | |
| 220 | // Check the version. |
| 221 | if (::memcmp(header->version, |
| 222 | RSINFO_VERSION, |
| 223 | sizeof((header->version)) != 0)) { |
| 224 | ALOGV("Mismatch the version of RS info file %s: (current) %s v.s. (file) " |
| 225 | "%s. Treat it as as a dirty cache.", input_filename, RSINFO_VERSION, |
| 226 | header->version); |
| 227 | goto bail; |
| 228 | } |
| 229 | |
| 230 | // Check the size. |
| 231 | if ((header->headerSize != sizeof(rsinfo::Header)) || |
| 232 | (header->dependencyTable.itemSize != sizeof(rsinfo::DependencyTableItem)) || |
| 233 | (header->pragmaList.itemSize != sizeof(rsinfo::PragmaItem)) || |
| 234 | (header->objectSlotList.itemSize != sizeof(rsinfo::ObjectSlotItem)) || |
| 235 | (header->exportVarNameList.itemSize != sizeof(rsinfo::ExportVarNameItem)) || |
| 236 | (header->exportFuncNameList.itemSize != sizeof(rsinfo::ExportFuncNameItem)) || |
| 237 | (header->exportForeachFuncList.itemSize != sizeof(rsinfo::ExportForeachFuncItem))) { |
| 238 | ALOGW("Corrupted RS info file %s! (unexpected size found)", input_filename); |
| 239 | goto bail; |
| 240 | } |
| 241 | |
| 242 | // Check the range. |
| 243 | #define LIST_DATA_RANGE(_list_header) \ |
| 244 | ((_list_header).offset + (_list_header).count * (_list_header).itemSize) |
| 245 | if (((header->headerSize + header->strPoolSize) > filesize) || |
| 246 | (LIST_DATA_RANGE(header->dependencyTable) > filesize) || |
| 247 | (LIST_DATA_RANGE(header->pragmaList) > filesize) || |
| 248 | (LIST_DATA_RANGE(header->objectSlotList) > filesize) || |
| 249 | (LIST_DATA_RANGE(header->exportVarNameList) > filesize) || |
| 250 | (LIST_DATA_RANGE(header->exportFuncNameList) > filesize) || |
| 251 | (LIST_DATA_RANGE(header->exportForeachFuncList) > filesize)) { |
| 252 | ALOGW("Corrupted RS info file %s! (data out of the range)", input_filename); |
| 253 | goto bail; |
| 254 | } |
| 255 | #undef LIST_DATA_RANGE |
| 256 | |
| 257 | // File seems ok, create result RSInfo object. |
| 258 | result = new (std::nothrow) RSInfo(header->strPoolSize); |
| 259 | if (result == NULL) { |
| 260 | ALOGE("Out of memory when create RSInfo object for %s!", input_filename); |
| 261 | goto bail; |
| 262 | } |
| 263 | |
| 264 | // Make advice on our access pattern. |
| 265 | map->advise(android::FileMap::SEQUENTIAL); |
| 266 | |
| 267 | // Copy the header. |
| 268 | ::memcpy(&result->mHeader, header, sizeof(rsinfo::Header)); |
| 269 | |
| 270 | if (header->strPoolSize > 0) { |
| 271 | // Copy the string pool. The string pool is immediately after the header at |
| 272 | // the offset header->headerSize. |
| 273 | if (result->mStringPool == NULL) { |
| 274 | ALOGE("Out of memory when allocate string pool for RS info file %s!", |
| 275 | input_filename); |
| 276 | goto bail; |
| 277 | } |
| 278 | ::memcpy(result->mStringPool, data + result->mHeader.headerSize, |
| 279 | result->mHeader.strPoolSize); |
| 280 | } |
| 281 | |
| 282 | // Populate all the data to the result object. |
| 283 | if (!helper_read_list<rsinfo::DependencyTableItem, DependencyTableTy> |
| 284 | (data, *result, header->dependencyTable, result->mDependencyTable)) { |
| 285 | goto bail; |
| 286 | } |
| 287 | |
| 288 | // Check dependency to see whether the cache is dirty or not. |
| 289 | if (!CheckDependency(*result, pInput.getName().c_str(), pDeps)) { |
| 290 | goto bail; |
| 291 | } |
| 292 | |
| 293 | if (!helper_read_list<rsinfo::PragmaItem, PragmaListTy> |
| 294 | (data, *result, header->pragmaList, result->mPragmas)) { |
| 295 | goto bail; |
| 296 | } |
| 297 | |
| 298 | if (!helper_read_list<rsinfo::ObjectSlotItem, ObjectSlotListTy> |
| 299 | (data, *result, header->objectSlotList, result->mObjectSlots)) { |
| 300 | goto bail; |
| 301 | } |
| 302 | |
| 303 | if (!helper_read_list<rsinfo::ExportVarNameItem, ExportVarNameListTy> |
| 304 | (data, *result, header->exportVarNameList, result->mExportVarNames)) { |
| 305 | goto bail; |
| 306 | } |
| 307 | |
| 308 | if (!helper_read_list<rsinfo::ExportFuncNameItem, ExportFuncNameListTy> |
| 309 | (data, *result, header->exportFuncNameList, result->mExportFuncNames)) { |
| 310 | goto bail; |
| 311 | } |
| 312 | |
| 313 | if (!helper_read_list<rsinfo::ExportForeachFuncItem, ExportForeachFuncListTy> |
| 314 | (data, *result, header->exportForeachFuncList, result->mExportForeachFuncs)) { |
| 315 | goto bail; |
| 316 | } |
| 317 | |
| 318 | // Clean up. |
| 319 | map->release(); |
| 320 | |
| 321 | return result; |
| 322 | |
| 323 | bail: |
| 324 | if (map != NULL) { |
| 325 | map->release(); |
| 326 | } |
| 327 | |
| 328 | delete result; |
| 329 | |
| 330 | return NULL; |
| 331 | } // RSInfo::ReadFromFile |