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 PragmaItem in the file
40 template<> inline bool
helper_read_list_item(const rsinfo::PragmaItem & pItem,const RSInfo & pInfo,RSInfo::PragmaListTy & pResult)41 helper_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
64 template<> inline bool
helper_read_list_item(const rsinfo::ObjectSlotItem & pItem,const RSInfo & pInfo,RSInfo::ObjectSlotListTy & pResult)65 helper_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
75 template<> inline bool
helper_read_list_item(const rsinfo::ExportVarNameItem & pItem,const RSInfo & pInfo,RSInfo::ExportVarNameListTy & pResult)76 helper_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
93 template<> inline bool
helper_read_list_item(const rsinfo::ExportFuncNameItem & pItem,const RSInfo & pInfo,RSInfo::ExportFuncNameListTy & pResult)94 helper_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
111 template<> inline bool
helper_read_list_item(const rsinfo::ExportForeachFuncItem & pItem,const RSInfo & pInfo,RSInfo::ExportForeachFuncListTy & pResult)112 helper_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 
128 template<typename ItemType, typename ItemContainer>
helper_read_list(const uint8_t * pData,const RSInfo & pInfo,const rsinfo::ListHeader & pHeader,ItemContainer & pResult)129 inline 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 
ReadFromFile(InputFile & pInput)149 RSInfo *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 
302 bail:
303   if (map != NULL) {
304     map->release();
305   }
306 
307   delete result;
308 
309   return NULL;
310 } // RSInfo::ReadFromFile
311