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