1 /*
2  * Copyright (C) 2018, 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 #include "aidl.h"
18 #include "aidl_language.h"
19 #include "import_resolver.h"
20 #include "logging.h"
21 #include "options.h"
22 
23 #include <map>
24 #include <string>
25 #include <vector>
26 
27 #include <android-base/result.h>
28 #include <android-base/strings.h>
29 
30 namespace android {
31 namespace aidl {
32 
33 using android::base::Error;
34 using android::base::Result;
35 using std::map;
36 using std::set;
37 using std::string;
38 using std::vector;
39 
get_strict_annotations(const AidlAnnotatable & node)40 static set<AidlAnnotation> get_strict_annotations(const AidlAnnotatable& node) {
41   // This must be symmetrical (if you can add something, you must be able to
42   // remove it). The reason is that we have no way of knowing which interface a
43   // server serves and which interface a client serves (e.g. a callback
44   // interface). Note that this is being overly lenient. It makes sense for
45   // newer code to start accepting nullable things. However, here, we don't know
46   // if the client of an interface or the server of an interface is newer.
47   //
48   // Here are two examples to demonstrate this:
49   // - a new implementation might change so that it no longer returns null
50   // values (remove @nullable)
51   // - a new implementation might start accepting null values (add @nullable)
52   static const set<AidlAnnotation::Type> kIgnoreAnnotations{
53       AidlAnnotation::Type::NULLABLE,
54       AidlAnnotation::Type::JAVA_DEBUG,
55       AidlAnnotation::Type::IMMUTABLE,
56   };
57   set<AidlAnnotation> annotations;
58   for (const AidlAnnotation& annotation : node.GetAnnotations()) {
59     if (kIgnoreAnnotations.find(annotation.GetType()) == kIgnoreAnnotations.end()) {
60       annotations.insert(annotation);
61     }
62   }
63   return annotations;
64 }
65 
have_compatible_annotations(const AidlAnnotatable & older,const AidlAnnotatable & newer)66 static bool have_compatible_annotations(const AidlAnnotatable& older,
67                                         const AidlAnnotatable& newer) {
68   set<AidlAnnotation> olderAnnotations = get_strict_annotations(older);
69   set<AidlAnnotation> newerAnnotations = get_strict_annotations(newer);
70 
71   if (olderAnnotations != newerAnnotations) {
72     const string from = older.ToString().empty() ? "(empty)" : older.ToString();
73     const string to = newer.ToString().empty() ? "(empty)" : newer.ToString();
74     AIDL_ERROR(newer) << "Changed annotations: " << from << " to " << to;
75     return false;
76   }
77   return true;
78 }
79 
are_compatible_types(const AidlTypeSpecifier & older,const AidlTypeSpecifier & newer)80 static bool are_compatible_types(const AidlTypeSpecifier& older, const AidlTypeSpecifier& newer) {
81   bool compatible = true;
82   if (older.ToString() != newer.ToString()) {
83     AIDL_ERROR(newer) << "Type changed: " << older.ToString() << " to " << newer.ToString() << ".";
84     compatible = false;
85   }
86   compatible &= have_compatible_annotations(older, newer);
87   return compatible;
88 }
89 
are_compatible_interfaces(const AidlInterface & older,const AidlInterface & newer)90 static bool are_compatible_interfaces(const AidlInterface& older, const AidlInterface& newer) {
91   bool compatible = true;
92   compatible &= have_compatible_annotations(older, newer);
93 
94   map<string, AidlMethod*> new_methods;
95   for (const auto& m : newer.AsInterface()->GetMethods()) {
96     new_methods.emplace(m->Signature(), m.get());
97   }
98 
99   for (const auto& old_m : older.AsInterface()->GetMethods()) {
100     const auto found = new_methods.find(old_m->Signature());
101     if (found == new_methods.end()) {
102       AIDL_ERROR(old_m) << "Removed or changed method: " << older.GetCanonicalName() << "."
103                         << old_m->Signature();
104       compatible = false;
105       continue;
106     }
107 
108     // Compare IDs to detect method reordering. IDs are assigned by their
109     // textual order, so if there is an ID mismatch, that means reordering
110     // has happened.
111     const auto new_m = found->second;
112 
113     if (old_m->IsOneway() != new_m->IsOneway()) {
114       AIDL_ERROR(new_m) << "Oneway attribute " << (old_m->IsOneway() ? "removed" : "added") << ": "
115                         << older.GetCanonicalName() << "." << old_m->Signature();
116       compatible = false;
117     }
118 
119     if (old_m->GetId() != new_m->GetId()) {
120       AIDL_ERROR(new_m) << "Transaction ID changed: " << older.GetCanonicalName() << "."
121                         << old_m->Signature() << " is changed from " << old_m->GetId() << " to "
122                         << new_m->GetId() << ".";
123       compatible = false;
124     }
125 
126     compatible &= are_compatible_types(old_m->GetType(), new_m->GetType());
127 
128     const auto& old_args = old_m->GetArguments();
129     const auto& new_args = new_m->GetArguments();
130     // this is guaranteed because arguments are part of AidlMethod::Signature()
131     CHECK(old_args.size() == new_args.size());
132     for (size_t i = 0; i < old_args.size(); i++) {
133       const AidlArgument& old_a = *(old_args.at(i));
134       const AidlArgument& new_a = *(new_args.at(i));
135       compatible &= are_compatible_types(old_a.GetType(), new_a.GetType());
136 
137       if (old_a.GetDirection() != new_a.GetDirection()) {
138         AIDL_ERROR(new_m) << "Direction changed: " << old_a.GetDirectionSpecifier() << " to "
139                           << new_a.GetDirectionSpecifier() << ".";
140         compatible = false;
141       }
142     }
143   }
144 
145   map<string, AidlConstantDeclaration*> new_constdecls;
146   for (const auto& c : newer.AsInterface()->GetConstantDeclarations()) {
147     new_constdecls.emplace(c->GetName(), c.get());
148   }
149 
150   for (const auto& old_c : older.AsInterface()->GetConstantDeclarations()) {
151     const auto found = new_constdecls.find(old_c->GetName());
152     if (found == new_constdecls.end()) {
153       AIDL_ERROR(old_c) << "Removed constant declaration: " << older.GetCanonicalName() << "."
154                         << old_c->GetName();
155       compatible = false;
156       continue;
157     }
158 
159     const auto new_c = found->second;
160     compatible &= are_compatible_types(old_c->GetType(), new_c->GetType());
161 
162     const string old_value = old_c->ValueString(AidlConstantValueDecorator);
163     const string new_value = new_c->ValueString(AidlConstantValueDecorator);
164     if (old_value != new_value) {
165       AIDL_ERROR(newer) << "Changed constant value: " << older.GetCanonicalName() << "."
166                         << old_c->GetName() << " from " << old_value << " to " << new_value << ".";
167       compatible = false;
168     }
169   }
170   return compatible;
171 }
172 
173 // returns whether the given type when defaulted will be accepted by
174 // unmarshalling code
has_usable_nil_type(const AidlTypeSpecifier & specifier)175 static bool has_usable_nil_type(const AidlTypeSpecifier& specifier) {
176   // TODO(b/155238508): fix for primitives
177 
178   // This technically only applies in C++, but even if both the client and the
179   // server of an interface are in Java at a particular point in time, where
180   // null is currently always acceptable, we want to make sure that versions
181   // of this service can work in native and future backends without a problem.
182   // Also, in that case, adding nullable does not hurt.
183   return specifier.IsNullable();
184 }
185 
are_compatible_parcelables(const AidlStructuredParcelable & older,const AidlStructuredParcelable & newer)186 static bool are_compatible_parcelables(const AidlStructuredParcelable& older,
187                                        const AidlStructuredParcelable& newer) {
188   const auto& old_fields = older.GetFields();
189   const auto& new_fields = newer.GetFields();
190   if (old_fields.size() > new_fields.size()) {
191     // you can add new fields only at the end
192     AIDL_ERROR(newer) << "Number of fields in " << older.GetCanonicalName() << " is reduced from "
193                       << old_fields.size() << " to " << new_fields.size() << ".";
194     return false;
195   }
196 
197   bool compatible = true;
198   for (size_t i = 0; i < old_fields.size(); i++) {
199     const auto& old_field = old_fields.at(i);
200     const auto& new_field = new_fields.at(i);
201     compatible &= are_compatible_types(old_field->GetType(), new_field->GetType());
202 
203     const string old_value = old_field->ValueString(AidlConstantValueDecorator);
204     const string new_value = new_field->ValueString(AidlConstantValueDecorator);
205     if (old_value != new_value) {
206       AIDL_ERROR(new_field) << "Changed default value: " << old_value << " to " << new_value << ".";
207       compatible = false;
208     }
209   }
210 
211   // Reordering of fields is an incompatible change.
212   for (size_t i = 0; i < new_fields.size(); i++) {
213     const auto& new_field = new_fields.at(i);
214     auto found = std::find_if(old_fields.begin(), old_fields.end(), [&new_field](const auto& f) {
215       return new_field->GetName() == f->GetName();
216     });
217     if (found != old_fields.end()) {
218       size_t old_index = std::distance(old_fields.begin(), found);
219       if (old_index != i) {
220         AIDL_ERROR(new_field) << "Reordered " << new_field->GetName() << " from " << old_index
221                               << " to " << i << ".";
222         compatible = false;
223       }
224     }
225   }
226 
227   for (size_t i = old_fields.size(); i < new_fields.size(); i++) {
228     const auto& new_field = new_fields.at(i);
229     if (!new_field->GetDefaultValue() && !has_usable_nil_type(new_field->GetType())) {
230       // Old API versions may suffer from the issue presented here. There is
231       // only a finite number in Android, which we must allow indefinitely.
232       struct HistoricalException {
233         std::string canonical;
234         std::string field;
235       };
236       static std::vector<HistoricalException> exceptions = {
237           {"android.net.DhcpResultsParcelable", "serverHostName"},
238           {"android.net.ResolverParamsParcel", "resolverOptions"},
239       };
240       bool excepted = false;
241       for (const HistoricalException& exception : exceptions) {
242         if (older.GetCanonicalName() == exception.canonical &&
243             new_field->GetName() == exception.field) {
244           excepted = true;
245           break;
246         }
247       }
248       if (excepted) continue;
249 
250       AIDL_ERROR(new_field)
251           << "Field '" << new_field->GetName()
252           << "' does not have a useful default in some backends. Please either provide a default "
253              "value for this field or mark the field as @nullable. This value or a null value will "
254              "be used automatically when an old version of this parcelable is sent to a process "
255              "which understands a new version of this parcelable. In order to make sure your code "
256              "continues to be backwards compatible, make sure the default or null value does not "
257              "cause a semantic change to this parcelable.";
258       compatible = false;
259     }
260   }
261   return compatible;
262 }
263 
are_compatible_enums(const AidlEnumDeclaration & older,const AidlEnumDeclaration & newer)264 static bool are_compatible_enums(const AidlEnumDeclaration& older,
265                                  const AidlEnumDeclaration& newer) {
266   if (!are_compatible_types(older.GetBackingType(), newer.GetBackingType())) {
267     AIDL_ERROR(newer) << "Changed backing types.";
268     return false;
269   }
270 
271   std::map<std::string, const AidlConstantValue*> old_enum_map;
272   for (const auto& enumerator : older.GetEnumerators()) {
273     old_enum_map[enumerator->GetName()] = enumerator->GetValue();
274   }
275   std::map<std::string, const AidlConstantValue*> new_enum_map;
276   for (const auto& enumerator : newer.GetEnumerators()) {
277     new_enum_map[enumerator->GetName()] = enumerator->GetValue();
278   }
279 
280   bool compatible = true;
281   for (const auto& [name, value] : old_enum_map) {
282     if (new_enum_map.find(name) == new_enum_map.end()) {
283       AIDL_ERROR(newer) << "Removed enumerator from " << older.GetCanonicalName() << ": " << name;
284       compatible = false;
285       continue;
286     }
287     const string old_value =
288         old_enum_map[name]->ValueString(older.GetBackingType(), AidlConstantValueDecorator);
289     const string new_value =
290         new_enum_map[name]->ValueString(newer.GetBackingType(), AidlConstantValueDecorator);
291     if (old_value != new_value) {
292       AIDL_ERROR(newer) << "Changed enumerator value: " << older.GetCanonicalName() << "::" << name
293                         << " from " << old_value << " to " << new_value << ".";
294       compatible = false;
295     }
296   }
297   return compatible;
298 }
299 
load_from_dir(const Options & options,const IoDelegate & io_delegate,const std::string & dir)300 static Result<AidlTypenames> load_from_dir(const Options& options, const IoDelegate& io_delegate,
301                                            const std::string& dir) {
302   AidlTypenames typenames;
303   for (const auto& file : io_delegate.ListFiles(dir)) {
304     if (!android::base::EndsWith(file, ".aidl")) continue;
305     if (internals::load_and_validate_aidl(file, options, io_delegate, &typenames,
306                                           nullptr /* imported_files */) != AidlError::OK) {
307       AIDL_ERROR(file) << "Failed to read.";
308       return Error();
309     }
310   }
311   return typenames;
312 }
313 
check_api(const Options & options,const IoDelegate & io_delegate)314 bool check_api(const Options& options, const IoDelegate& io_delegate) {
315   CHECK(options.IsStructured());
316   CHECK(options.InputFiles().size() == 2) << "--checkapi requires two inputs "
317                                           << "but got " << options.InputFiles().size();
318   auto old_tns = load_from_dir(options, io_delegate, options.InputFiles().at(0));
319   if (!old_tns.ok()) {
320     return false;
321   }
322   auto new_tns = load_from_dir(options, io_delegate, options.InputFiles().at(1));
323   if (!new_tns.ok()) {
324     return false;
325   }
326 
327   std::vector<AidlDefinedType*> old_types = old_tns->AllDefinedTypes();
328   std::vector<AidlDefinedType*> new_types = new_tns->AllDefinedTypes();
329 
330   map<string, AidlDefinedType*> new_map;
331   for (const auto t : new_types) {
332     new_map.emplace(t->GetCanonicalName(), t);
333   }
334 
335   bool compatible = true;
336   for (const auto old_type : old_types) {
337     const auto found = new_map.find(old_type->GetCanonicalName());
338     if (found == new_map.end()) {
339       AIDL_ERROR(old_type) << "Removed type: " << old_type->GetCanonicalName();
340       compatible = false;
341       continue;
342     }
343     const auto new_type = found->second;
344 
345     if (old_type->AsInterface() != nullptr) {
346       if (new_type->AsInterface() == nullptr) {
347         AIDL_ERROR(new_type) << "Type mismatch: " << old_type->GetCanonicalName()
348                              << " is changed from " << old_type->GetPreprocessDeclarationName()
349                              << " to " << new_type->GetPreprocessDeclarationName();
350         compatible = false;
351         continue;
352       }
353       compatible &=
354           are_compatible_interfaces(*(old_type->AsInterface()), *(new_type->AsInterface()));
355     } else if (old_type->AsStructuredParcelable() != nullptr) {
356       if (new_type->AsStructuredParcelable() == nullptr) {
357         AIDL_ERROR(new_type) << "Parcelable" << new_type->GetCanonicalName()
358                              << " is not structured. ";
359         compatible = false;
360         continue;
361       }
362       compatible &= are_compatible_parcelables(*(old_type->AsStructuredParcelable()),
363                                                *(new_type->AsStructuredParcelable()));
364     } else if (old_type->AsEnumDeclaration() != nullptr) {
365       if (new_type->AsEnumDeclaration() == nullptr) {
366         AIDL_ERROR(new_type) << "Type mismatch: " << old_type->GetCanonicalName()
367                              << " is changed from " << old_type->GetPreprocessDeclarationName()
368                              << " to " << new_type->GetPreprocessDeclarationName();
369         compatible = false;
370         continue;
371       }
372       compatible &=
373           are_compatible_enums(*(old_type->AsEnumDeclaration()), *(new_type->AsEnumDeclaration()));
374     } else {
375       AIDL_ERROR(old_type) << "Unsupported type " << old_type->GetPreprocessDeclarationName()
376                            << " for " << old_type->GetCanonicalName();
377       compatible = false;
378     }
379   }
380 
381   return compatible;
382 }
383 
384 }  // namespace aidl
385 }  // namespace android
386