1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "apk_validator.h"
16
17 #include <iostream>
18 #include <sstream>
19
20 #include "androidfw/ZipFileRO.h"
21
22 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
23
24 namespace {
25
26 const char kTfProtoFilename[] = "tuningfork.proto";
27 const char kDevProtoFilename[] = "dev_tuningfork.proto";
28 const char kSettingsFilename[] = "tuningfork_settings.bin";
29
30 int kMaxInstrumentationKeys = 256; // Sanity check
31
32 template <typename T>
operator <<(std::ostream & o,const std::vector<T> & vec)33 std::ostream& operator<<(std::ostream& o, const std::vector<T>& vec) {
34 o << "[";
35 bool first = true;
36 for (auto& i : vec) {
37 if (!first)
38 o << ",";
39 else
40 first = false;
41 o << i;
42 }
43 o << "]";
44 return o;
45 }
46
47 } // anonymous namespace
48
49 namespace tuningfork {
50
AddError(const std::string & file_name,int line,int column,const std::string & message)51 void ErrorCollector::AddError(const std::string& file_name, int line, int column,
52 const std::string& message) {
53 std::cerr << "Error in: " << file_name << " line: " << line << " column: "
54 << column << " message: " << message << std::endl;
55 }
56
57 #define ZERROR(CODE, MSG) {last_error_code_ = CODE; \
58 {std::stringstream str; str << MSG; last_error_msg_ = str.str(); } \
59 return nullptr;}
60
ZipSourceTree(const std::shared_ptr<android::ZipFileRO> & zip_file,const std::string & include_path)61 ZipSourceTree::ZipSourceTree(const std::shared_ptr<android::ZipFileRO>& zip_file,
62 const std::string& include_path)
63 : zip_file_(zip_file), include_path_(include_path), last_error_code_(0) {
64 }
65
66 pb::io::ZeroCopyInputStream*
Open(const std::string & relative_path)67 ZipSourceTree::Open(const std::string& relative_path) {
68 std::string path = include_path_ + relative_path;
69 auto it = file_cache_.find(path);
70 if (file_cache_.end() == it) {
71 android::ZipEntryRO entry = zip_file_->findEntryByName(path.c_str());
72 if (entry == nullptr) {
73 ZERROR(ERROR_NO_DEV_PROTO, "Could not find " << path);
74 }
75 uint32_t file_len = 0;
76 if (!zip_file_->getEntryInfo(entry, NULL, &file_len,
77 NULL, NULL, NULL, NULL)) {
78 ZERROR(ERROR_CANT_READ_PROTO, "Could not read " << path);
79 }
80 it = file_cache_.insert({path,{}}).first;
81 it->second.resize(file_len);
82 if (!zip_file_->uncompressEntry(entry, it->second.data(), file_len)) {
83 file_cache_.erase(it);
84 ZERROR(ERROR_CANT_UNCOMPRESS_PROTO, "Could not uncompress " << path);
85 }
86 }
87 return new pb::io::ArrayInputStream(it->second.data(), it->second.size());
88 }
89
GetLastErrorMessage()90 std::string ZipSourceTree::GetLastErrorMessage() {
91 return last_error_msg_;
92 }
93
GetLastErrorCode()94 int ZipSourceTree::GetLastErrorCode() {
95 return last_error_code_;
96 }
97
ZipFile() const98 const std::shared_ptr<android::ZipFileRO>& ZipSourceTree::ZipFile() const {
99 return zip_file_;
100 }
101
IncludePath() const102 std::string ZipSourceTree::IncludePath() const {
103 return include_path_;
104 }
105
ApkValidator(const std::shared_ptr<android::ZipFileRO> & zip_file,const std::string & asset_path,bool debug)106 ApkValidator::ApkValidator(const std::shared_ptr<android::ZipFileRO>& zip_file,
107 const std::string& asset_path, bool debug)
108 : source_tree_(zip_file, asset_path), debug_(debug) {
109 importer_ = std::unique_ptr<pb::compiler::Importer>(
110 new pb::compiler::Importer(&source_tree_, &error_collector_));
111 }
112
Validate(bool enforce_enums_in_annotations,bool check_dev_fidelity_params)113 int ApkValidator::Validate(bool enforce_enums_in_annotations,
114 bool check_dev_fidelity_params) {
115 // Import the dev proto
116 const pb::FileDescriptor* fdesc = importer_->Import(kDevProtoFilename);
117 if (!fdesc)
118 ERROR(source_tree_.GetLastErrorCode(),
119 source_tree_.GetLastErrorMessage());
120 if (debug_)
121 std::cout << "Uncompressed " << kDevProtoFilename << std::endl;
122 DebugFileDesc(fdesc);
123
124 // Check Annotations
125 auto adesc = FindMessageIgnoringScope(fdesc, "Annotation");
126 if (!adesc)
127 ERROR(ERROR_GETTING_ANNOTATION, "Error finding Annotation");
128 std::vector<int> def_ann_enum_size;
129 auto aok = ValidateAnnotation(adesc, enforce_enums_in_annotations,
130 def_ann_enum_size);
131 if (aok != NO_ERROR)
132 ERROR(aok, "Error in Annotations");
133
134 // Check FidelityParams
135 auto fpdesc = FindMessageIgnoringScope(fdesc, "FidelityParams");
136 if (!fpdesc)
137 ERROR(ERROR_GETTING_FIDELITYPARAMS, "Error finding FidelityParams");
138 auto fpok = ValidateFidelityParams(fpdesc);
139 if (fpok != NO_ERROR)
140 ERROR(fpok, "Error in FidelityParams");
141
142 // Check the settings
143 const pb::FileDescriptor* tfdesc = importer_->Import(kTfProtoFilename);
144 if (!tfdesc)
145 ERROR(source_tree_.GetLastErrorCode(),
146 source_tree_.GetLastErrorMessage());
147 if (debug_)
148 std::cout << "Uncompressed " << kTfProtoFilename << std::endl;
149 DebugFileDesc(tfdesc);
150 auto sdesc = FindMessageIgnoringScope(tfdesc, "Settings");
151 if (!sdesc)
152 ERROR(ERROR_GETTING_SETTINGS, "Error finding Settings");
153 auto sok = ValidateSettings(sdesc, def_ann_enum_size);
154 if (sok != NO_ERROR)
155 ERROR(sok, "Error validating settings");
156
157 if (check_dev_fidelity_params) {
158 return ValidateDevFidelityParams();
159 }
160 return NO_ERROR;
161 }
162
ValidateAnnotation(const pb::Descriptor * desc,bool enforce_enums_in_annotations,std::vector<int> & enum_sizes)163 int ApkValidator::ValidateAnnotation(const pb::Descriptor* desc,
164 bool enforce_enums_in_annotations,
165 std::vector<int>& enum_sizes) {
166 enum_sizes.clear();
167 DebugDesc(desc);
168 if (desc->oneof_decl_count() > 0 || desc->nested_type_count() > 0
169 || desc->extension_count() > 0 || desc->extension_range_count() > 0)
170 ERROR(ERROR_ANNOTATION_TOO_COMPLEX, "Annotation too complex");
171 auto n = desc->field_count();
172 for (int i=0; i < n; ++i) {
173 auto field = desc->field(i);
174 if (field->type() == pb::FieldDescriptor::TYPE_ENUM) {
175 enum_sizes.push_back(field->enum_type()->value_count());
176 }
177 else {
178 if (enforce_enums_in_annotations) {
179 ERROR(ERROR_ANNOTATION_ONLY_ENUMS,
180 "Annotation can only contain enums");
181 } else {
182 // Still check it's an int or bool
183 switch (field->type()) {
184 case pb::FieldDescriptor::TYPE_INT32:
185 case pb::FieldDescriptor::TYPE_UINT32:
186 enum_sizes.push_back(-1);
187 break;
188 case pb::FieldDescriptor::TYPE_BOOL:
189 enum_sizes.push_back(2);
190 break;
191 default:
192 ERROR(ERROR_ANNOTATION_ONLY_ENUMS,
193 "Annotation can only contain enums, ints or bools");
194 }
195 }
196 }
197 }
198 return NO_ERROR;
199 }
200
ValidateFidelityParams(const pb::Descriptor * desc)201 int ApkValidator::ValidateFidelityParams(const pb::Descriptor* desc) {
202 DebugDesc(desc);
203 if (desc->oneof_decl_count() > 0 || desc->nested_type_count() > 0
204 || desc->extension_count() > 0 || desc->extension_range_count() > 0)
205 ERROR(ERROR_FIDELITYPARAMS_TOO_COMPLEX, "FidelityParams too complex");
206 auto n = desc->field_count();
207 for (int i=0; i < n; ++i) {
208 auto field = desc->field(i);
209 if (field->type() == pb::FieldDescriptor::TYPE_GROUP
210 || field->type() == pb::FieldDescriptor::TYPE_MESSAGE
211 || field->type() == pb::FieldDescriptor::TYPE_BYTES)
212 ERROR(ERROR_FIDELITYPARAMS_BAD_TYPE,
213 "FidelityParams can only contain scalars");
214 }
215 return NO_ERROR;
216 }
217
ValidateSettings(const pb::Descriptor * sdesc,const std::vector<int> & def_ann_enum_size)218 int ApkValidator::ValidateSettings(const pb::Descriptor* sdesc,
219 const std::vector<int>& def_ann_enum_size) {
220 auto settings_proto = factory_.GetPrototype(sdesc);
221 if (!settings_proto)
222 ERROR(ERROR_GETTING_SETTINGS, "Error making Settings prototype");
223 pb::Message* m = settings_proto->New();
224 if (!m)
225 ERROR(ERROR_GETTING_SETTINGS, "Error making Settings object");
226 std::unique_ptr<pb::io::ArrayInputStream> settings_bin(
227 dynamic_cast<pb::io::ArrayInputStream*>(
228 source_tree_.Open(kSettingsFilename)));
229 if (!settings_bin)
230 ERROR(ERROR_GETTING_SETTINGS, "Error reading tuningfork_settings.bin");
231 if (debug_)
232 std::cout << "Uncompressed " << kSettingsFilename << std::endl;
233 const void* ptr=0;
234 int sz = 0;
235 if (!settings_bin->Next(&ptr,&sz))
236 ERROR(ERROR_GETTING_SETTINGS, "Error reading tuningfork settings data");
237 m->ParseFromString((const char*)ptr);
238 const pb::Reflection* refl = m->GetReflection();
239 auto aggregation_strategy_field = m->GetDescriptor()
240 ->FindFieldByName("aggregation_strategy");
241 const pb::Message& agg_strat = refl->GetMessage(*m, aggregation_strategy_field);
242 const pb::Reflection* as_refl = agg_strat.GetReflection();
243 auto max_ikeys_field = agg_strat.GetDescriptor()
244 ->FindFieldByName("max_instrumentation_keys");
245 auto max_ikeys = as_refl->GetInt32(agg_strat, max_ikeys_field);
246 if (debug_)
247 std::cout << "Max instrumentation keys = " << max_ikeys << std::endl;
248 if (max_ikeys < 1 || max_ikeys>kMaxInstrumentationKeys)
249 ERROR(ERROR_BAD_MAX_INSTRUMENTATION_KEYS, "max_ikeys = " << max_ikeys);
250 auto ann_enum_size_field = agg_strat.GetDescriptor()
251 ->FindFieldByName("annotation_enum_size");
252 std::vector<int> ann_enum_size;
253 int n = as_refl->FieldSize(agg_strat, ann_enum_size_field);
254 for (int i=0; i < n; ++i)
255 ann_enum_size.push_back(as_refl->GetRepeatedInt32(agg_strat,
256 ann_enum_size_field,
257 i));
258 if (debug_) {
259 std::cout << "Deduced annotation enum sizes from Annotation: "
260 << def_ann_enum_size << std::endl;
261 std::cout << "Annotation enum sizes in settings file: " << ann_enum_size << std::endl;
262 }
263 if (ann_enum_size.size() != def_ann_enum_size.size())
264 ERROR(ERROR_BAD_ANNOTATION_ENUM_SIZE,
265 "Annotation enum size length bad: "
266 << ann_enum_size.size() << "!=" << def_ann_enum_size.size());
267 for (int i=0; i < ann_enum_size.size(); ++i) {
268 if (def_ann_enum_size[i] != -1 && ann_enum_size[i] != def_ann_enum_size[i])
269 ERROR(ERROR_BAD_ANNOTATION_ENUM_SIZE,
270 "Bad annotation enum size: "
271 << ann_enum_size[i] << "!=" << def_ann_enum_size[i]);
272 }
273 return NO_ERROR;
274 }
275
ValidateDevFidelityParams()276 int ApkValidator::ValidateDevFidelityParams() {
277 void* cookie;
278 android::ZipFileRO* zip_file = source_tree_.ZipFile().get();
279 std::string prefix = source_tree_.IncludePath() + "dev_tuningfork_fidelityparams_";
280 char suffix[] = "bin";
281 zip_file->startIteration(&cookie, prefix.c_str(), suffix);
282 int fp_count = 0;
283 for (auto entry = zip_file->nextEntry(cookie);
284 entry; entry=zip_file->nextEntry(cookie)) {
285 ++fp_count;
286 }
287 zip_file->endIteration(cookie);
288 if (debug_)
289 std::cout << "Found " << fp_count << " files matching "
290 << prefix + "*.bin" << std::endl;
291 if (fp_count == 0)
292 ERROR(ERROR_NO_DEV_FIDELITYPARAMS, "No dev fidelity params present");
293 return NO_ERROR;
294 }
295
296 // Find a message type, ignoring the scope
297 const pb::Descriptor*
FindMessageIgnoringScope(const pb::FileDescriptor * fdesc,const std::string & name)298 ApkValidator::FindMessageIgnoringScope(const pb::FileDescriptor* fdesc,
299 const std::string& name) {
300 int n = fdesc->message_type_count();
301 for (int i=0; i<n; ++i) {
302 auto desc = fdesc->message_type(i);
303 if (desc->name() == name) return desc;
304 }
305 return nullptr;
306 }
307
DebugFileDesc(const pb::FileDescriptor * fdesc)308 void ApkValidator::DebugFileDesc(const pb::FileDescriptor* fdesc) {
309 if (debug_) {
310 std::cout << fdesc->name()
311 << ": messages: " << fdesc->message_type_count()
312 << ", dependencies: " << fdesc->dependency_count()
313 << ", extensions: " << fdesc->extension_count()
314 << ", enums: " << fdesc->enum_type_count()
315 << std::endl;
316 }
317 }
318
DebugDesc(const pb::Descriptor * desc)319 void ApkValidator::DebugDesc(const pb::Descriptor* desc) {
320 if (debug_) {
321 std::cout << desc->name()
322 << ": fields: " << desc->field_count()
323 << ", one-ofs: " << desc->oneof_decl_count()
324 << ", nested: " << desc->nested_type_count()
325 << ", enums: " << desc->enum_type_count()
326 << ", extensions: " << desc->extension_count()
327 << ", extension ranges: " << desc->extension_range_count()
328 << std::endl;
329 }
330 }
331
332 }
333