blob: 6d9b6fbe4085db28ca9ab1a502520b1b71c32377 [file] [log] [blame]
David Brazdil2b9c35b2018-01-12 15:44:43 +00001/*
2 * Copyright (C) 2017 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 <fstream>
18#include <iostream>
David Brazdil0b6de0c2018-06-28 11:56:41 +010019#include <map>
20#include <set>
David Brazdil2b9c35b2018-01-12 15:44:43 +000021
22#include "android-base/stringprintf.h"
23#include "android-base/strings.h"
24
David Sehr79e26072018-04-06 17:58:50 -070025#include "base/mem_map.h"
David Sehrc431b9d2018-03-02 12:01:51 -080026#include "base/os.h"
David Brazdil2b9c35b2018-01-12 15:44:43 +000027#include "base/unix_file/fd_file.h"
28#include "dex/art_dex_file_loader.h"
Mathieu Chartier396dc082018-08-06 12:29:57 -070029#include "dex/class_accessor-inl.h"
David Brazdil2b9c35b2018-01-12 15:44:43 +000030#include "dex/dex_file-inl.h"
David Sehr67bf42e2018-02-26 16:43:04 -080031#include "dex/hidden_api_access_flags.h"
David Brazdil2b9c35b2018-01-12 15:44:43 +000032
33namespace art {
34
35static int original_argc;
36static char** original_argv;
37
38static std::string CommandLine() {
39 std::vector<std::string> command;
40 for (int i = 0; i < original_argc; ++i) {
41 command.push_back(original_argv[i]);
42 }
43 return android::base::Join(command, ' ');
44}
45
46static void UsageErrorV(const char* fmt, va_list ap) {
47 std::string error;
48 android::base::StringAppendV(&error, fmt, ap);
49 LOG(ERROR) << error;
50}
51
52static void UsageError(const char* fmt, ...) {
53 va_list ap;
54 va_start(ap, fmt);
55 UsageErrorV(fmt, ap);
56 va_end(ap);
57}
58
59NO_RETURN static void Usage(const char* fmt, ...) {
60 va_list ap;
61 va_start(ap, fmt);
62 UsageErrorV(fmt, ap);
63 va_end(ap);
64
65 UsageError("Command: %s", CommandLine().c_str());
David Brazdil003e64b2018-06-27 13:20:52 +010066 UsageError("Usage: hiddenapi [command_name] [options]...");
David Brazdil2b9c35b2018-01-12 15:44:43 +000067 UsageError("");
David Brazdil003e64b2018-06-27 13:20:52 +010068 UsageError(" Command \"encode\": encode API list membership in boot dex files");
69 UsageError(" --dex=<filename>: dex file which belongs to boot class path,");
70 UsageError(" the file will be overwritten");
David Brazdil2b9c35b2018-01-12 15:44:43 +000071 UsageError("");
David Brazdil003e64b2018-06-27 13:20:52 +010072 UsageError(" --light-greylist=<filename>:");
73 UsageError(" --dark-greylist=<filename>:");
74 UsageError(" --blacklist=<filename>:");
75 UsageError(" text files with signatures of methods/fields to be annotated");
David Brazdil2b9c35b2018-01-12 15:44:43 +000076 UsageError("");
David Brazdil0b6de0c2018-06-28 11:56:41 +010077 UsageError(" Command \"list\": dump lists of public and private API");
78 UsageError(" --boot-dex=<filename>: dex file which belongs to boot class path");
David Brazdil345c0ed2018-08-03 10:26:44 +010079 UsageError(" --stub-classpath=<filenames>: colon-separated list of dex/apk files");
80 UsageError(" which form API stubs of boot class path. Multiple classpaths can");
81 UsageError(" be specified");
David Brazdil0b6de0c2018-06-28 11:56:41 +010082 UsageError("");
83 UsageError(" --out-public=<filename>: output file for a list of all public APIs");
84 UsageError(" --out-private=<filename>: output file for a list of all private APIs");
85 UsageError("");
David Brazdil2b9c35b2018-01-12 15:44:43 +000086
87 exit(EXIT_FAILURE);
88}
89
David Brazdil0b6de0c2018-06-28 11:56:41 +010090template<typename E>
91static bool Contains(const std::vector<E>& vec, const E& elem) {
92 return std::find(vec.begin(), vec.end(), elem) != vec.end();
93}
94
Mathieu Chartier396dc082018-08-06 12:29:57 -070095class DexClass : public ClassAccessor {
David Brazdil2b9c35b2018-01-12 15:44:43 +000096 public:
Mathieu Chartier396dc082018-08-06 12:29:57 -070097 explicit DexClass(const ClassAccessor& accessor) : ClassAccessor(accessor) {}
David Brazdil2b9c35b2018-01-12 15:44:43 +000098
Mathieu Chartier396dc082018-08-06 12:29:57 -070099 const uint8_t* GetData() const { return dex_file_.GetClassData(GetClassDef()); }
David Brazdil2b9c35b2018-01-12 15:44:43 +0000100
Mathieu Chartier396dc082018-08-06 12:29:57 -0700101 const dex::TypeIndex GetSuperclassIndex() const { return GetClassDef().superclass_idx_; }
David Brazdil0b6de0c2018-06-28 11:56:41 +0100102
103 bool HasSuperclass() const { return dex_file_.IsTypeIndexValid(GetSuperclassIndex()); }
104
David Brazdil0b6de0c2018-06-28 11:56:41 +0100105 std::string GetSuperclassDescriptor() const {
Mathieu Chartier396dc082018-08-06 12:29:57 -0700106 return HasSuperclass() ? dex_file_.StringByTypeIdx(GetSuperclassIndex()) : "";
David Brazdil0b6de0c2018-06-28 11:56:41 +0100107 }
108
109 std::set<std::string> GetInterfaceDescriptors() const {
110 std::set<std::string> list;
Mathieu Chartier396dc082018-08-06 12:29:57 -0700111 const DexFile::TypeList* ifaces = dex_file_.GetInterfacesList(GetClassDef());
David Brazdil0b6de0c2018-06-28 11:56:41 +0100112 for (uint32_t i = 0; ifaces != nullptr && i < ifaces->Size(); ++i) {
113 list.insert(dex_file_.StringByTypeIdx(ifaces->GetTypeItem(i).type_idx_));
114 }
115 return list;
116 }
117
David Brazdil345c0ed2018-08-03 10:26:44 +0100118 inline bool IsPublic() const { return HasAccessFlags(kAccPublic); }
David Brazdil0b6de0c2018-06-28 11:56:41 +0100119
120 inline bool Equals(const DexClass& other) const {
Mathieu Chartier396dc082018-08-06 12:29:57 -0700121 bool equals = strcmp(GetDescriptor(), other.GetDescriptor()) == 0;
David Brazdil0b6de0c2018-06-28 11:56:41 +0100122 if (equals) {
123 // TODO(dbrazdil): Check that methods/fields match as well once b/111116543 is fixed.
124 CHECK_EQ(GetAccessFlags(), other.GetAccessFlags());
125 CHECK_EQ(GetSuperclassDescriptor(), other.GetSuperclassDescriptor());
126 CHECK(GetInterfaceDescriptors() == other.GetInterfaceDescriptors());
127 }
128 return equals;
129 }
David Brazdil2b9c35b2018-01-12 15:44:43 +0000130
131 private:
Mathieu Chartier396dc082018-08-06 12:29:57 -0700132 uint32_t GetAccessFlags() const { return GetClassDef().access_flags_; }
David Brazdil0b6de0c2018-06-28 11:56:41 +0100133 bool HasAccessFlags(uint32_t mask) const { return (GetAccessFlags() & mask) == mask; }
David Brazdil2b9c35b2018-01-12 15:44:43 +0000134};
135
136class DexMember {
137 public:
Mathieu Chartier396dc082018-08-06 12:29:57 -0700138 DexMember(const DexClass& klass, const ClassAccessor::Field& item)
139 : klass_(klass), item_(item), is_method_(false) {
140 DCHECK_EQ(GetFieldId().class_idx_, klass.GetClassIdx());
141 }
142
143 DexMember(const DexClass& klass, const ClassAccessor::Method& item)
144 : klass_(klass), item_(item), is_method_(true) {
145 DCHECK_EQ(GetMethodId().class_idx_, klass.GetClassIdx());
David Brazdil2b9c35b2018-01-12 15:44:43 +0000146 }
147
David Brazdil0b6de0c2018-06-28 11:56:41 +0100148 inline const DexClass& GetDeclaringClass() const { return klass_; }
149
David Brazdil2b9c35b2018-01-12 15:44:43 +0000150 // Sets hidden bits in access flags and writes them back into the DEX in memory.
Mathieu Chartier396dc082018-08-06 12:29:57 -0700151 // Note that this will not update the cached data of the class accessor
David Brazdil2b9c35b2018-01-12 15:44:43 +0000152 // until it iterates over this item again and therefore will fail a CHECK if
153 // it is called multiple times on the same DexMember.
Mathieu Chartier396dc082018-08-06 12:29:57 -0700154 void SetHidden(HiddenApiAccessFlags::ApiList value) const {
155 const uint32_t old_flags = item_.GetRawAccessFlags();
David Brazdilf6a8a552018-01-15 18:10:50 +0000156 const uint32_t new_flags = HiddenApiAccessFlags::EncodeForDex(old_flags, value);
David Brazdil2b9c35b2018-01-12 15:44:43 +0000157 CHECK_EQ(UnsignedLeb128Size(new_flags), UnsignedLeb128Size(old_flags));
158
159 // Locate the LEB128-encoded access flags in class data.
160 // `ptr` initially points to the next ClassData item. We iterate backwards
161 // until we hit the terminating byte of the previous Leb128 value.
Mathieu Chartier396dc082018-08-06 12:29:57 -0700162 const uint8_t* ptr = item_.GetDataPointer();
David Brazdil0b6de0c2018-06-28 11:56:41 +0100163 if (IsMethod()) {
Alex Light1a824a52018-01-26 15:45:30 -0800164 ptr = ReverseSearchUnsignedLeb128(ptr);
Mathieu Chartier396dc082018-08-06 12:29:57 -0700165 DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), GetMethod().GetCodeItemOffset());
David Brazdil2b9c35b2018-01-12 15:44:43 +0000166 }
Alex Light1a824a52018-01-26 15:45:30 -0800167 ptr = ReverseSearchUnsignedLeb128(ptr);
168 DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), old_flags);
David Brazdil2b9c35b2018-01-12 15:44:43 +0000169
170 // Overwrite the access flags.
171 UpdateUnsignedLeb128(const_cast<uint8_t*>(ptr), new_flags);
172 }
173
Mathieu Chartier396dc082018-08-06 12:29:57 -0700174 inline bool IsMethod() const { return is_method_; }
175 inline bool IsVirtualMethod() const { return IsMethod() && !GetMethod().IsStaticOrDirect(); }
David Brazdil345c0ed2018-08-03 10:26:44 +0100176 inline bool IsConstructor() const { return IsMethod() && HasAccessFlags(kAccConstructor); }
David Brazdil0b6de0c2018-06-28 11:56:41 +0100177
David Brazdil345c0ed2018-08-03 10:26:44 +0100178 inline bool IsPublicOrProtected() const {
179 return HasAccessFlags(kAccPublic) || HasAccessFlags(kAccProtected);
David Brazdil0b6de0c2018-06-28 11:56:41 +0100180 }
181
David Brazdil2b9c35b2018-01-12 15:44:43 +0000182 // Constructs a string with a unique signature of this class member.
183 std::string GetApiEntry() const {
184 std::stringstream ss;
Mathieu Chartier396dc082018-08-06 12:29:57 -0700185 ss << klass_.GetDescriptor() << "->" << GetName() << (IsMethod() ? "" : ":")
186 << GetSignature();
David Brazdil2b9c35b2018-01-12 15:44:43 +0000187 return ss.str();
188 }
189
Mathieu Chartier396dc082018-08-06 12:29:57 -0700190 inline bool operator==(const DexMember& other) const {
David Brazdil0b6de0c2018-06-28 11:56:41 +0100191 // These need to match if they should resolve to one another.
192 bool equals = IsMethod() == other.IsMethod() &&
193 GetName() == other.GetName() &&
194 GetSignature() == other.GetSignature();
195
196 // Sanity checks if they do match.
197 if (equals) {
198 CHECK_EQ(IsVirtualMethod(), other.IsVirtualMethod());
199 }
200
201 return equals;
202 }
203
David Brazdil2b9c35b2018-01-12 15:44:43 +0000204 private:
Mathieu Chartier396dc082018-08-06 12:29:57 -0700205 inline uint32_t GetAccessFlags() const { return item_.GetAccessFlags(); }
David Brazdil0b6de0c2018-06-28 11:56:41 +0100206 inline uint32_t HasAccessFlags(uint32_t mask) const { return (GetAccessFlags() & mask) == mask; }
207
208 inline std::string GetName() const {
Mathieu Chartier396dc082018-08-06 12:29:57 -0700209 return IsMethod() ? item_.GetDexFile().GetMethodName(GetMethodId())
210 : item_.GetDexFile().GetFieldName(GetFieldId());
David Brazdil0b6de0c2018-06-28 11:56:41 +0100211 }
212
213 inline std::string GetSignature() const {
Mathieu Chartier396dc082018-08-06 12:29:57 -0700214 return IsMethod() ? item_.GetDexFile().GetMethodSignature(GetMethodId()).ToString()
215 : item_.GetDexFile().GetFieldTypeDescriptor(GetFieldId());
216 }
217
218 inline const ClassAccessor::Method& GetMethod() const {
219 DCHECK(IsMethod());
220 return down_cast<const ClassAccessor::Method&>(item_);
David Brazdil0b6de0c2018-06-28 11:56:41 +0100221 }
222
David Brazdil2b9c35b2018-01-12 15:44:43 +0000223 inline const DexFile::MethodId& GetMethodId() const {
David Brazdil0b6de0c2018-06-28 11:56:41 +0100224 DCHECK(IsMethod());
Mathieu Chartier396dc082018-08-06 12:29:57 -0700225 return item_.GetDexFile().GetMethodId(item_.GetIndex());
David Brazdil2b9c35b2018-01-12 15:44:43 +0000226 }
227
228 inline const DexFile::FieldId& GetFieldId() const {
David Brazdil0b6de0c2018-06-28 11:56:41 +0100229 DCHECK(!IsMethod());
Mathieu Chartier396dc082018-08-06 12:29:57 -0700230 return item_.GetDexFile().GetFieldId(item_.GetIndex());
David Brazdil2b9c35b2018-01-12 15:44:43 +0000231 }
232
David Brazdil2b9c35b2018-01-12 15:44:43 +0000233 const DexClass& klass_;
Mathieu Chartier396dc082018-08-06 12:29:57 -0700234 const ClassAccessor::BaseItem& item_;
235 const bool is_method_;
David Brazdil2b9c35b2018-01-12 15:44:43 +0000236};
237
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100238class ClassPath final {
David Brazdil2b9c35b2018-01-12 15:44:43 +0000239 public:
David Brazdil0b6de0c2018-06-28 11:56:41 +0100240 ClassPath(const std::vector<std::string>& dex_paths, bool open_writable) {
241 OpenDexFiles(dex_paths, open_writable);
242 }
243
244 template<typename Fn>
245 void ForEachDexClass(Fn fn) {
246 for (auto& dex_file : dex_files_) {
Mathieu Chartier396dc082018-08-06 12:29:57 -0700247 for (ClassAccessor accessor : dex_file->GetClasses()) {
248 fn(DexClass(accessor));
David Brazdil0b6de0c2018-06-28 11:56:41 +0100249 }
250 }
David Brazdil2b9c35b2018-01-12 15:44:43 +0000251 }
252
David Brazdil003e64b2018-06-27 13:20:52 +0100253 template<typename Fn>
254 void ForEachDexMember(Fn fn) {
Mathieu Chartier396dc082018-08-06 12:29:57 -0700255 ForEachDexClass([&fn](const DexClass& klass) {
256 for (const ClassAccessor::Field& field : klass.GetFields()) {
257 fn(DexMember(klass, field));
258 }
259 for (const ClassAccessor::Method& method : klass.GetMethods()) {
260 fn(DexMember(klass, method));
David Brazdil2b9c35b2018-01-12 15:44:43 +0000261 }
David Brazdil0b6de0c2018-06-28 11:56:41 +0100262 });
David Brazdil2b9c35b2018-01-12 15:44:43 +0000263 }
264
265 void UpdateDexChecksums() {
266 for (auto& dex_file : dex_files_) {
267 // Obtain a writeable pointer to the dex header.
268 DexFile::Header* header = const_cast<DexFile::Header*>(&dex_file->GetHeader());
269 // Recalculate checksum and overwrite the value in the header.
270 header->checksum_ = dex_file->CalculateChecksum();
271 }
272 }
273
David Brazdil003e64b2018-06-27 13:20:52 +0100274 private:
David Brazdil0b6de0c2018-06-28 11:56:41 +0100275 void OpenDexFiles(const std::vector<std::string>& dex_paths, bool open_writable) {
David Brazdil003e64b2018-06-27 13:20:52 +0100276 ArtDexFileLoader dex_loader;
277 std::string error_msg;
David Brazdil003e64b2018-06-27 13:20:52 +0100278
David Brazdil0b6de0c2018-06-28 11:56:41 +0100279 if (open_writable) {
280 for (const std::string& filename : dex_paths) {
281 File fd(filename.c_str(), O_RDWR, /* check_usage */ false);
282 CHECK_NE(fd.Fd(), -1) << "Unable to open file '" << filename << "': " << strerror(errno);
283
284 // Memory-map the dex file with MAP_SHARED flag so that changes in memory
285 // propagate to the underlying file. We run dex file verification as if
286 // the dex file was not in boot claass path to check basic assumptions,
287 // such as that at most one of public/private/protected flag is set.
288 // We do those checks here and skip them when loading the processed file
289 // into boot class path.
290 std::unique_ptr<const DexFile> dex_file(dex_loader.OpenDex(fd.Release(),
291 /* location */ filename,
292 /* verify */ true,
293 /* verify_checksum */ true,
294 /* mmap_shared */ true,
295 &error_msg));
296 CHECK(dex_file.get() != nullptr) << "Open failed for '" << filename << "' " << error_msg;
297 CHECK(dex_file->IsStandardDexFile()) << "Expected a standard dex file '" << filename << "'";
298 CHECK(dex_file->EnableWrite())
299 << "Failed to enable write permission for '" << filename << "'";
300 dex_files_.push_back(std::move(dex_file));
301 }
302 } else {
303 for (const std::string& filename : dex_paths) {
304 bool success = dex_loader.Open(filename.c_str(),
305 /* location */ filename,
306 /* verify */ true,
307 /* verify_checksum */ true,
308 &error_msg,
309 &dex_files_);
310 CHECK(success) << "Open failed for '" << filename << "' " << error_msg;
311 }
David Brazdil003e64b2018-06-27 13:20:52 +0100312 }
313 }
314
David Brazdil0b6de0c2018-06-28 11:56:41 +0100315 // Opened dex files. Note that these are opened as `const` but may be written into.
David Brazdil003e64b2018-06-27 13:20:52 +0100316 std::vector<std::unique_ptr<const DexFile>> dex_files_;
317};
318
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100319class HierarchyClass final {
David Brazdil0b6de0c2018-06-28 11:56:41 +0100320 public:
321 HierarchyClass() {}
322
323 void AddDexClass(const DexClass& klass) {
324 CHECK(dex_classes_.empty() || klass.Equals(dex_classes_.front()));
325 dex_classes_.push_back(klass);
326 }
327
328 void AddExtends(HierarchyClass& parent) {
329 CHECK(!Contains(extends_, &parent));
330 CHECK(!Contains(parent.extended_by_, this));
331 extends_.push_back(&parent);
332 parent.extended_by_.push_back(this);
333 }
334
335 const DexClass& GetOneDexClass() const {
336 CHECK(!dex_classes_.empty());
337 return dex_classes_.front();
338 }
339
340 // See comment on Hierarchy::ForEachResolvableMember.
341 template<typename Fn>
342 bool ForEachResolvableMember(const DexMember& other, Fn fn) {
343 return ForEachResolvableMember_Impl(other, fn) != ResolutionResult::kNotFound;
344 }
345
David Brazdil345c0ed2018-08-03 10:26:44 +0100346 // Returns true if this class contains at least one member matching `other`.
347 bool HasMatchingMember(const DexMember& other) {
348 return ForEachMatchingMember(
349 other, [](const DexMember&) { return true; }) != ResolutionResult::kNotFound;
350 }
351
352 // Recursively iterates over all subclasses of this class and invokes `fn`
353 // on each one. If `fn` returns false for a particular subclass, exploring its
354 // subclasses is skipped.
355 template<typename Fn>
356 void ForEachSubClass(Fn fn) {
357 for (HierarchyClass* subclass : extended_by_) {
358 if (fn(subclass)) {
359 subclass->ForEachSubClass(fn);
360 }
361 }
362 }
363
David Brazdil0b6de0c2018-06-28 11:56:41 +0100364 private:
365 // Result of resolution which takes into account whether the member was found
366 // for the first time or not. This is just a performance optimization to prevent
367 // re-visiting previously visited members.
368 // Note that order matters. When accumulating results, we always pick the maximum.
369 enum class ResolutionResult {
370 kNotFound,
371 kFoundOld,
372 kFoundNew,
373 };
374
375 inline ResolutionResult Accumulate(ResolutionResult a, ResolutionResult b) {
376 return static_cast<ResolutionResult>(
377 std::max(static_cast<unsigned>(a), static_cast<unsigned>(b)));
378 }
379
380 template<typename Fn>
381 ResolutionResult ForEachResolvableMember_Impl(const DexMember& other, Fn fn) {
382 // First try to find a member matching `other` in this class.
383 ResolutionResult foundInClass = ForEachMatchingMember(other, fn);
384
385 switch (foundInClass) {
386 case ResolutionResult::kFoundOld:
387 // A matching member was found and previously explored. All subclasses
388 // must have been explored too.
389 break;
390
391 case ResolutionResult::kFoundNew:
392 // A matching member was found and this was the first time it was visited.
393 // If it is a virtual method, visit all methods overriding/implementing it too.
394 if (other.IsVirtualMethod()) {
395 for (HierarchyClass* subclass : extended_by_) {
396 subclass->ForEachOverridingMember(other, fn);
397 }
398 }
399 break;
400
401 case ResolutionResult::kNotFound:
402 // A matching member was not found in this class. Explore the superclasses
403 // and implemented interfaces.
404 for (HierarchyClass* superclass : extends_) {
405 foundInClass = Accumulate(
406 foundInClass, superclass->ForEachResolvableMember_Impl(other, fn));
407 }
408 break;
409 }
410
411 return foundInClass;
412 }
413
414 template<typename Fn>
415 ResolutionResult ForEachMatchingMember(const DexMember& other, Fn fn) {
416 ResolutionResult found = ResolutionResult::kNotFound;
Mathieu Chartier396dc082018-08-06 12:29:57 -0700417 auto compare_member = [&](const DexMember& member) {
418 if (member == other) {
419 found = Accumulate(found, fn(member) ? ResolutionResult::kFoundNew
420 : ResolutionResult::kFoundOld);
421 }
422 };
David Brazdil0b6de0c2018-06-28 11:56:41 +0100423 for (const DexClass& dex_class : dex_classes_) {
Mathieu Chartier396dc082018-08-06 12:29:57 -0700424 for (const ClassAccessor::Field& field : dex_class.GetFields()) {
425 compare_member(DexMember(dex_class, field));
426 }
427 for (const ClassAccessor::Method& method : dex_class.GetMethods()) {
428 compare_member(DexMember(dex_class, method));
David Brazdil0b6de0c2018-06-28 11:56:41 +0100429 }
430 }
431 return found;
432 }
433
434 template<typename Fn>
435 void ForEachOverridingMember(const DexMember& other, Fn fn) {
436 CHECK(other.IsVirtualMethod());
437 ResolutionResult found = ForEachMatchingMember(other, fn);
438 if (found == ResolutionResult::kFoundOld) {
439 // No need to explore further.
440 return;
441 } else {
442 for (HierarchyClass* subclass : extended_by_) {
443 subclass->ForEachOverridingMember(other, fn);
444 }
445 }
446 }
447
448 // DexClass entries of this class found across all the provided dex files.
449 std::vector<DexClass> dex_classes_;
450
451 // Classes which this class inherits, or interfaces which it implements.
452 std::vector<HierarchyClass*> extends_;
453
454 // Classes which inherit from this class.
455 std::vector<HierarchyClass*> extended_by_;
456};
457
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100458class Hierarchy final {
David Brazdil0b6de0c2018-06-28 11:56:41 +0100459 public:
David Brazdil345c0ed2018-08-03 10:26:44 +0100460 explicit Hierarchy(ClassPath& classpath) : classpath_(classpath) {
David Brazdil0b6de0c2018-06-28 11:56:41 +0100461 BuildClassHierarchy();
462 }
463
464 // Perform an operation for each member of the hierarchy which could potentially
465 // be the result of method/field resolution of `other`.
466 // The function `fn` should accept a DexMember reference and return true if
467 // the member was changed. This drives a performance optimization which only
468 // visits overriding members the first time the overridden member is visited.
469 // Returns true if at least one resolvable member was found.
470 template<typename Fn>
471 bool ForEachResolvableMember(const DexMember& other, Fn fn) {
472 HierarchyClass* klass = FindClass(other.GetDeclaringClass().GetDescriptor());
473 return (klass != nullptr) && klass->ForEachResolvableMember(other, fn);
474 }
475
David Brazdil345c0ed2018-08-03 10:26:44 +0100476 // Returns true if `member`, which belongs to this classpath, is visible to
477 // code in child class loaders.
478 bool IsMemberVisible(const DexMember& member) {
479 if (!member.IsPublicOrProtected()) {
480 // Member is private or package-private. Cannot be visible.
481 return false;
482 } else if (member.GetDeclaringClass().IsPublic()) {
483 // Member is public or protected, and class is public. It must be visible.
484 return true;
485 } else if (member.IsConstructor()) {
486 // Member is public or protected constructor and class is not public.
487 // Must be hidden because it cannot be implicitly exposed by a subclass.
488 return false;
489 } else {
490 // Member is public or protected method, but class is not public. Check if
491 // it is exposed through a public subclass.
492 // Example code (`foo` exposed by ClassB):
493 // class ClassA { public void foo() { ... } }
494 // public class ClassB extends ClassA {}
495 HierarchyClass* klass = FindClass(member.GetDeclaringClass().GetDescriptor());
496 CHECK(klass != nullptr);
497 bool visible = false;
498 klass->ForEachSubClass([&visible, &member](HierarchyClass* subclass) {
499 if (subclass->HasMatchingMember(member)) {
500 // There is a member which matches `member` in `subclass`, either
501 // a virtual method overriding `member` or a field overshadowing
502 // `member`. In either case, `member` remains hidden.
503 CHECK(member.IsVirtualMethod() || !member.IsMethod());
504 return false; // do not explore deeper
505 } else if (subclass->GetOneDexClass().IsPublic()) {
506 // `subclass` inherits and exposes `member`.
507 visible = true;
508 return false; // do not explore deeper
509 } else {
510 // `subclass` inherits `member` but does not expose it.
511 return true; // explore deeper
512 }
513 });
514 return visible;
515 }
516 }
517
David Brazdil0b6de0c2018-06-28 11:56:41 +0100518 private:
519 HierarchyClass* FindClass(const std::string& descriptor) {
520 auto it = classes_.find(descriptor);
521 if (it == classes_.end()) {
522 return nullptr;
523 } else {
524 return &it->second;
525 }
526 }
527
528 void BuildClassHierarchy() {
529 // Create one HierarchyClass entry in `classes_` per class descriptor
530 // and add all DexClass objects with the same descriptor to that entry.
Mathieu Chartier396dc082018-08-06 12:29:57 -0700531 classpath_.ForEachDexClass([this](const DexClass& klass) {
David Brazdil0b6de0c2018-06-28 11:56:41 +0100532 classes_[klass.GetDescriptor()].AddDexClass(klass);
533 });
534
535 // Connect each HierarchyClass to its successors and predecessors.
536 for (auto& entry : classes_) {
537 HierarchyClass& klass = entry.second;
538 const DexClass& dex_klass = klass.GetOneDexClass();
539
540 if (!dex_klass.HasSuperclass()) {
541 CHECK(dex_klass.GetInterfaceDescriptors().empty())
542 << "java/lang/Object should not implement any interfaces";
543 continue;
544 }
545
546 HierarchyClass* superclass = FindClass(dex_klass.GetSuperclassDescriptor());
547 CHECK(superclass != nullptr);
548 klass.AddExtends(*superclass);
549
550 for (const std::string& iface_desc : dex_klass.GetInterfaceDescriptors()) {
551 HierarchyClass* iface = FindClass(iface_desc);
552 CHECK(iface != nullptr);
553 klass.AddExtends(*iface);
554 }
555 }
556 }
557
David Brazdil345c0ed2018-08-03 10:26:44 +0100558 ClassPath& classpath_;
David Brazdil0b6de0c2018-06-28 11:56:41 +0100559 std::map<std::string, HierarchyClass> classes_;
560};
561
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100562class HiddenApi final {
David Brazdil003e64b2018-06-27 13:20:52 +0100563 public:
564 HiddenApi() {}
565
566 void Run(int argc, char** argv) {
567 switch (ParseArgs(argc, argv)) {
568 case Command::kEncode:
569 EncodeAccessFlags();
570 break;
David Brazdil0b6de0c2018-06-28 11:56:41 +0100571 case Command::kList:
572 ListApi();
573 break;
David Brazdil003e64b2018-06-27 13:20:52 +0100574 }
575 }
576
577 private:
578 enum class Command {
David Brazdil003e64b2018-06-27 13:20:52 +0100579 kEncode,
David Brazdil0b6de0c2018-06-28 11:56:41 +0100580 kList,
David Brazdil003e64b2018-06-27 13:20:52 +0100581 };
582
583 Command ParseArgs(int argc, char** argv) {
584 // Skip over the binary's path.
585 argv++;
586 argc--;
587
588 if (argc > 0) {
589 const StringPiece command(argv[0]);
590 if (command == "encode") {
591 for (int i = 1; i < argc; ++i) {
592 const StringPiece option(argv[i]);
593 if (option.starts_with("--dex=")) {
594 boot_dex_paths_.push_back(option.substr(strlen("--dex=")).ToString());
595 } else if (option.starts_with("--light-greylist=")) {
596 light_greylist_path_ = option.substr(strlen("--light-greylist=")).ToString();
597 } else if (option.starts_with("--dark-greylist=")) {
598 dark_greylist_path_ = option.substr(strlen("--dark-greylist=")).ToString();
599 } else if (option.starts_with("--blacklist=")) {
600 blacklist_path_ = option.substr(strlen("--blacklist=")).ToString();
601 } else {
602 Usage("Unknown argument '%s'", option.data());
603 }
604 }
605 return Command::kEncode;
David Brazdil0b6de0c2018-06-28 11:56:41 +0100606 } else if (command == "list") {
607 for (int i = 1; i < argc; ++i) {
608 const StringPiece option(argv[i]);
609 if (option.starts_with("--boot-dex=")) {
610 boot_dex_paths_.push_back(option.substr(strlen("--boot-dex=")).ToString());
David Brazdil345c0ed2018-08-03 10:26:44 +0100611 } else if (option.starts_with("--stub-classpath=")) {
612 stub_classpaths_.push_back(android::base::Split(
613 option.substr(strlen("--stub-classpath=")).ToString(), ":"));
David Brazdil0b6de0c2018-06-28 11:56:41 +0100614 } else if (option.starts_with("--out-public=")) {
615 out_public_path_ = option.substr(strlen("--out-public=")).ToString();
616 } else if (option.starts_with("--out-private=")) {
617 out_private_path_ = option.substr(strlen("--out-private=")).ToString();
618 } else {
619 Usage("Unknown argument '%s'", option.data());
620 }
621 }
622 return Command::kList;
David Brazdil003e64b2018-06-27 13:20:52 +0100623 } else {
624 Usage("Unknown command '%s'", command.data());
625 }
626 } else {
627 Usage("No command specified");
628 }
629 }
630
631 void EncodeAccessFlags() {
632 if (boot_dex_paths_.empty()) {
633 Usage("No boot DEX files specified");
634 }
635
636 // Load dex signatures.
637 std::map<std::string, HiddenApiAccessFlags::ApiList> api_list;
638 OpenApiFile(light_greylist_path_, api_list, HiddenApiAccessFlags::kLightGreylist);
639 OpenApiFile(dark_greylist_path_, api_list, HiddenApiAccessFlags::kDarkGreylist);
640 OpenApiFile(blacklist_path_, api_list, HiddenApiAccessFlags::kBlacklist);
641
642 // Open all dex files.
David Brazdil345c0ed2018-08-03 10:26:44 +0100643 ClassPath boot_classpath(boot_dex_paths_, /* open_writable */ true);
David Brazdil003e64b2018-06-27 13:20:52 +0100644
645 // Set access flags of all members.
Mathieu Chartier396dc082018-08-06 12:29:57 -0700646 boot_classpath.ForEachDexMember([&api_list](const DexMember& boot_member) {
David Brazdil003e64b2018-06-27 13:20:52 +0100647 auto it = api_list.find(boot_member.GetApiEntry());
Mathieu Chartier396dc082018-08-06 12:29:57 -0700648 boot_member.SetHidden(it == api_list.end() ? HiddenApiAccessFlags::kWhitelist : it->second);
David Brazdil003e64b2018-06-27 13:20:52 +0100649 });
650
David Brazdil345c0ed2018-08-03 10:26:44 +0100651 boot_classpath.UpdateDexChecksums();
David Brazdil003e64b2018-06-27 13:20:52 +0100652 }
653
654 void OpenApiFile(const std::string& path,
655 std::map<std::string, HiddenApiAccessFlags::ApiList>& api_list,
656 HiddenApiAccessFlags::ApiList membership) {
657 if (path.empty()) {
658 return;
659 }
660
661 std::ifstream api_file(path, std::ifstream::in);
662 CHECK(!api_file.fail()) << "Unable to open file '" << path << "' " << strerror(errno);
663
664 for (std::string line; std::getline(api_file, line);) {
665 CHECK(api_list.find(line) == api_list.end())
666 << "Duplicate entry: " << line << " (" << api_list[line] << " and " << membership << ")";
667 api_list.emplace(line, membership);
668 }
669 api_file.close();
670 }
David Brazdil2b9c35b2018-01-12 15:44:43 +0000671
David Brazdil0b6de0c2018-06-28 11:56:41 +0100672 void ListApi() {
673 if (boot_dex_paths_.empty()) {
674 Usage("No boot DEX files specified");
David Brazdil345c0ed2018-08-03 10:26:44 +0100675 } else if (stub_classpaths_.empty()) {
David Brazdil0b6de0c2018-06-28 11:56:41 +0100676 Usage("No stub DEX files specified");
677 } else if (out_public_path_.empty()) {
678 Usage("No public API output path specified");
679 } else if (out_private_path_.empty()) {
680 Usage("No private API output path specified");
681 }
682
683 // Complete list of boot class path members. The associated boolean states
684 // whether it is public (true) or private (false).
685 std::map<std::string, bool> boot_members;
686
687 // Deduplicate errors before printing them.
688 std::set<std::string> unresolved;
689
690 // Open all dex files.
David Brazdil345c0ed2018-08-03 10:26:44 +0100691 ClassPath boot_classpath(boot_dex_paths_, /* open_writable */ false);
692 Hierarchy boot_hierarchy(boot_classpath);
David Brazdil0b6de0c2018-06-28 11:56:41 +0100693
694 // Mark all boot dex members private.
Mathieu Chartier396dc082018-08-06 12:29:57 -0700695 boot_classpath.ForEachDexMember([&boot_members](const DexMember& boot_member) {
David Brazdil0b6de0c2018-06-28 11:56:41 +0100696 boot_members[boot_member.GetApiEntry()] = false;
697 });
698
699 // Resolve each SDK dex member against the framework and mark it white.
David Brazdil345c0ed2018-08-03 10:26:44 +0100700 for (const std::vector<std::string>& stub_classpath_dex : stub_classpaths_) {
701 ClassPath stub_classpath(stub_classpath_dex, /* open_writable */ false);
702 Hierarchy stub_hierarchy(stub_classpath);
703 stub_classpath.ForEachDexMember(
Mathieu Chartier396dc082018-08-06 12:29:57 -0700704 [&stub_hierarchy, &boot_hierarchy, &boot_members, &unresolved](
705 const DexMember& stub_member) {
David Brazdil345c0ed2018-08-03 10:26:44 +0100706 if (!stub_hierarchy.IsMemberVisible(stub_member)) {
707 // Typically fake constructors and inner-class `this` fields.
708 return;
709 }
710 bool resolved = boot_hierarchy.ForEachResolvableMember(
711 stub_member,
Mathieu Chartier396dc082018-08-06 12:29:57 -0700712 [&boot_members](const DexMember& boot_member) {
David Brazdil345c0ed2018-08-03 10:26:44 +0100713 std::string entry = boot_member.GetApiEntry();
714 auto it = boot_members.find(entry);
715 CHECK(it != boot_members.end());
716 if (it->second) {
717 return false; // has been marked before
718 } else {
719 it->second = true;
720 return true; // marked for the first time
721 }
722 });
723 if (!resolved) {
724 unresolved.insert(stub_member.GetApiEntry());
725 }
726 });
727 }
David Brazdil0b6de0c2018-06-28 11:56:41 +0100728
729 // Print errors.
730 for (const std::string& str : unresolved) {
731 LOG(WARNING) << "unresolved: " << str;
732 }
733
734 // Write into public/private API files.
735 std::ofstream file_public(out_public_path_.c_str());
736 std::ofstream file_private(out_private_path_.c_str());
737 for (const std::pair<std::string, bool> entry : boot_members) {
738 if (entry.second) {
739 file_public << entry.first << std::endl;
740 } else {
741 file_private << entry.first << std::endl;
742 }
743 }
744 file_public.close();
745 file_private.close();
746 }
747
David Brazdil2b9c35b2018-01-12 15:44:43 +0000748 // Paths to DEX files which should be processed.
David Brazdil003e64b2018-06-27 13:20:52 +0100749 std::vector<std::string> boot_dex_paths_;
David Brazdil345c0ed2018-08-03 10:26:44 +0100750
751 // Set of public API stub classpaths. Each classpath is formed by a list
752 // of DEX/APK files in the order they appear on the classpath.
753 std::vector<std::vector<std::string>> stub_classpaths_;
David Brazdil2b9c35b2018-01-12 15:44:43 +0000754
755 // Paths to text files which contain the lists of API members.
756 std::string light_greylist_path_;
757 std::string dark_greylist_path_;
758 std::string blacklist_path_;
David Brazdil0b6de0c2018-06-28 11:56:41 +0100759
760 // Paths to text files to which we will output list of all API members.
761 std::string out_public_path_;
762 std::string out_private_path_;
David Brazdil2b9c35b2018-01-12 15:44:43 +0000763};
764
765} // namespace art
766
767int main(int argc, char** argv) {
David Brazdil003e64b2018-06-27 13:20:52 +0100768 android::base::InitLogging(argv);
769 art::MemMap::Init();
770 art::HiddenApi().Run(argc, argv);
771 return EXIT_SUCCESS;
David Brazdil2b9c35b2018-01-12 15:44:43 +0000772}