blob: 035209a481df9f9f21f01329eb21472f87c4cf70 [file] [log] [blame]
Zonr Chang255cbc82012-04-12 13:29:43 +08001/*
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 Chang80232dd2012-04-12 15:38:53 +080021#include "bcc/RenderScript/RSInfo.h"
Zonr Chang255cbc82012-04-12 13:29:43 +080022
23#include <new>
24
25#include <utils/FileMap.h>
26
Zonr Changb519fe32012-04-12 16:44:01 +080027#include "bcc/Support/Log.h"
Zonr Chang80232dd2012-04-12 15:38:53 +080028#include "bcc/Support/InputFile.h"
Zonr Chang255cbc82012-04-12 13:29:43 +080029
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
Stephen Hines7dfc4d82012-05-03 12:25:21 -0700176RSInfo *RSInfo::ReadFromFile(InputFile &pInput,
177 const RSScript::SourceDependencyListTy &pDeps) {
Zonr Chang255cbc82012-04-12 13:29:43 +0800178 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