• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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