RSInfoReader.cpp revision 1e2adce6df4414d827149ec563c9c89f21ea7426
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 "RSInfo.h"
22
23#include <new>
24
25#include <utils/FileMap.h>
26
27#include "DebugHelper.h"
28#include "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 DependencyTableItem in the file
40template<> inline bool
41helper_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
67template<> inline bool
68helper_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
91template<> inline bool
92helper_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
102template<> inline bool
103helper_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
120template<> inline bool
121helper_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
138template<> inline bool
139helper_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
155template<typename ItemType, typename ItemContainer>
156inline 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
176RSInfo *RSInfo::ReadFromFile(InputFile &pInput,
177                             const RSScript::SourceDependencyListTy &pDeps) {
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
323bail:
324  if (map != NULL) {
325    map->release();
326  }
327
328  delete result;
329
330  return NULL;
331} // RSInfo::ReadFromFile
332