android系统源码编译报错问题分析处理--持续更新
一、build/make/core/base_rules.mk:232: error: packages/services/Car/service: LOCAL_BUILT_MODULE and LOCAL_INSTALLED_MODULE must not be defined by component makefiles
出现此错误时,需要检查Android.mk中include $(CLEAR_VARS)及include $(BUILD_XXX...)是否一一对应了,如果有类似下边的写法,就需要修正
错误:
......
include $(CLEAR_VARS)
......
include $(BUILD_MULTI_PREBUILT)
......
include $(BUILD_STATIC_JAVA_LIBRARY)
......
include $(BUILD_PACKAGE)
include $(CLEAR_VARS) 正确:
include $(CLEAR_VARS)
......
include $(BUILD_MULTI_PREBUILT) include $(CLEAR_VARS)
......
include $(BUILD_STATIC_JAVA_LIBRARY) include $(CLEAR_VARS)
......
include $(BUILD_PACKAGE)
二、错误: 程序包androidx.annotation不存在,需要在 Android.mk 中添加如下,根据自己的依赖进行添加
LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx.recyclerview_recyclerview \
androidx.preference_preference \
androidx.appcompat_appcompat \
androidx.annotation_annotation \
androidx.legacy_legacy-preference-v14 \
androidx.leanback_leanback-preference \
androidx.leanback_leanback \
三、javadoc: 错误 - 在 doclet 类com.google.doclava.Doclava中, 方法start已抛出异常错误java.lang.reflect.InvocationTargetException
java.lang.IllegalArgumentException: Unable to find IBtMusicCmd.java. This is usually because doclava has been asked to generate stubs for a file that isn't present in the list of input source files but exists in the input classpath.
IBtMusicCmd是我的aidl文件,代码都编译通过了,没有出现依赖问题,但是最后报出这个错,查了两天才发现这个问题应该是javadoc的版本太低了,我找到了这个系统文件进行了暴力修改后编译正常,但是是否存在隐患还不确定
解决办法:
直接找到external\doclava\src\com\google\doclava\Stubs.java,然后在53行添加if(true) return;如下!目的就是不执行此文件的操作
public class Stubs {
public static void writeStubsAndApi(String stubsDir, String apiFile, String dexApiFile,
String keepListFile, String removedApiFile, String removedDexApiFile, String exactApiFile,
String privateApiFile, String privateDexApiFile, HashSet<String> stubPackages,
HashSet<String> stubImportPackages, boolean stubSourceOnly) {
if(true) return;
如果为了安全一点,也可以按照下边的方式,只判断是自己的这个模块就跳过就好了,源代码里三个地方添加以下代码,“android.car.xxxx.bt”需要替换为自己冲突的模块包名
if(cl.containingPackage().name().contains("android.car.xxxx.bt")){
System.out.println("=======android.car.xxxx.bt=============continue");
continue;
}
1 /*
2 * Copyright (C) 2010 Google Inc.
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 package com.google.doclava;
18
19 import java.io.BufferedOutputStream;
20 import java.io.BufferedReader;
21 import java.io.ByteArrayOutputStream;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29 import java.io.PrintStream;
30 import java.nio.charset.StandardCharsets;
31 import java.nio.file.Files;
32 import java.nio.file.Paths;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Scanner;
43 import java.util.Set;
44 import java.util.function.Predicate;
45 import java.util.regex.Pattern;
46 import java.util.stream.Collectors;
47
48 public class Stubs {
49 public static void writeStubsAndApi(String stubsDir, String apiFile, String dexApiFile,
50 String keepListFile, String removedApiFile, String removedDexApiFile, String exactApiFile,
51 String privateApiFile, String privateDexApiFile, HashSet<String> stubPackages,
52 HashSet<String> stubImportPackages, boolean stubSourceOnly) {
53 //if(true) return;
54 // figure out which classes we need
55 final HashSet<ClassInfo> notStrippable = new HashSet<ClassInfo>();
56 Collection<ClassInfo> all = Converter.allClasses();
57 Map<PackageInfo, List<ClassInfo>> allClassesByPackage = null;
58 PrintStream apiWriter = null;
59 PrintStream dexApiWriter = null;
60 PrintStream keepListWriter = null;
61 PrintStream removedApiWriter = null;
62 PrintStream removedDexApiWriter = null;
63 PrintStream exactApiWriter = null;
64 PrintStream privateApiWriter = null;
65 PrintStream privateDexApiWriter = null;
66
67 if (apiFile != null) {
68 try {
69 File xml = new File(apiFile);
70 xml.getParentFile().mkdirs();
71 apiWriter = new PrintStream(new BufferedOutputStream(new FileOutputStream(xml)));
72 } catch (FileNotFoundException e) {
73 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(apiFile, 0, 0),
74 "Cannot open file for write.");
75 }
76 }
77 if (dexApiFile != null) {
78 try {
79 File dexApi = new File(dexApiFile);
80 dexApi.getParentFile().mkdirs();
81 dexApiWriter = new PrintStream(new BufferedOutputStream(new FileOutputStream(dexApi)));
82 } catch (FileNotFoundException e) {
83 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(dexApiFile, 0, 0),
84 "Cannot open file for write.");
85 }
86 }
87 if (keepListFile != null) {
88 try {
89 File keepList = new File(keepListFile);
90 keepList.getParentFile().mkdirs();
91 keepListWriter = new PrintStream(new BufferedOutputStream(new FileOutputStream(keepList)));
92 } catch (FileNotFoundException e) {
93 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(keepListFile, 0, 0),
94 "Cannot open file for write.");
95 }
96 }
97 if (removedApiFile != null) {
98 try {
99 File removedApi = new File(removedApiFile);
100 removedApi.getParentFile().mkdirs();
101 removedApiWriter = new PrintStream(
102 new BufferedOutputStream(new FileOutputStream(removedApi)));
103 } catch (FileNotFoundException e) {
104 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(removedApiFile, 0, 0),
105 "Cannot open file for write");
106 }
107 }
108 if (removedDexApiFile != null) {
109 try {
110 File removedDexApi = new File(removedDexApiFile);
111 removedDexApi.getParentFile().mkdirs();
112 removedDexApiWriter = new PrintStream(
113 new BufferedOutputStream(new FileOutputStream(removedDexApi)));
114 } catch (FileNotFoundException e) {
115 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(removedDexApiFile, 0, 0),
116 "Cannot open file for write");
117 }
118 }
119 if (exactApiFile != null) {
120 try {
121 File exactApi = new File(exactApiFile);
122 exactApi.getParentFile().mkdirs();
123 exactApiWriter = new PrintStream(
124 new BufferedOutputStream(new FileOutputStream(exactApi)));
125 } catch (FileNotFoundException e) {
126 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(exactApiFile, 0, 0),
127 "Cannot open file for write");
128 }
129 }
130 if (privateApiFile != null) {
131 try {
132 File privateApi = new File(privateApiFile);
133 privateApi.getParentFile().mkdirs();
134 privateApiWriter = new PrintStream(
135 new BufferedOutputStream(new FileOutputStream(privateApi)));
136 } catch (FileNotFoundException e) {
137 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(privateApiFile, 0, 0),
138 "Cannot open file for write");
139 }
140 }
141 if (privateDexApiFile != null) {
142 try {
143 File privateDexApi = new File(privateDexApiFile);
144 privateDexApi.getParentFile().mkdirs();
145 privateDexApiWriter = new PrintStream(
146 new BufferedOutputStream(new FileOutputStream(privateDexApi)));
147 } catch (FileNotFoundException e) {
148 Errors.error(Errors.IO_ERROR, new SourcePositionInfo(privateDexApiFile, 0, 0),
149 "Cannot open file for write");
150 }
151 }
152 // If a class is public or protected, not hidden, not imported and marked as included,
153 // then we can't strip it
154 for (ClassInfo cl : all) {
155 if(cl.containingPackage().name().contains("android.car.xxxx.bt")){
156 System.out.println("=======android.car.xxxx.bt=============continue");
157 continue;
158 }
159 if (cl.checkLevel() && cl.isIncluded()) {
160 cantStripThis(cl, notStrippable, "0:0", stubImportPackages);
161 }
162 }
163
164 // complain about anything that looks includeable but is not supposed to
165 // be written, e.g. hidden things
166 for (ClassInfo cl : notStrippable) {
167 if(cl.containingPackage().name().contains("android.car.xxxx.bt")){
168 System.out.println("=======android.car.xxxx.bt=============continue");
169 continue;
170 }
171 if (!cl.isHiddenOrRemoved()) {
172 for (MethodInfo m : cl.selfMethods()) {
173 if (m.isHiddenOrRemoved()) {
174 Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Reference to unavailable method "
175 + m.name());
176 } else if (m.isDeprecated()) {
177 // don't bother reporting deprecated methods
178 // unless they are public
179 Errors.error(Errors.DEPRECATED, m.position(), "Method " + cl.qualifiedName() + "."
180 + m.name() + " is deprecated");
181 }
182
183 ClassInfo hiddenClass = findHiddenClasses(m.returnType(), stubImportPackages);
184 if (null != hiddenClass) {
185 if (hiddenClass.qualifiedName() == m.returnType().asClassInfo().qualifiedName()) {
186 // Return type is hidden
187 Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Method " + cl.qualifiedName()
188 + "." + m.name() + " returns unavailable type " + hiddenClass.name());
189 } else {
190 // Return type contains a generic parameter
191 Errors.error(Errors.HIDDEN_TYPE_PARAMETER, m.position(), "Method " + cl.qualifiedName()
192 + "." + m.name() + " returns unavailable type " + hiddenClass.name()
193 + " as a type parameter");
194 }
195 }
196
197 for (ParameterInfo p : m.parameters()) {
198 TypeInfo t = p.type();
199 if (!t.isPrimitive()) {
200 hiddenClass = findHiddenClasses(t, stubImportPackages);
201 if (null != hiddenClass) {
202 if (hiddenClass.qualifiedName() == t.asClassInfo().qualifiedName()) {
203 // Parameter type is hidden
204 Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(),
205 "Parameter of unavailable type " + t.fullName() + " in " + cl.qualifiedName()
206 + "." + m.name() + "()");
207 } else {
208 // Parameter type contains a generic parameter
209 Errors.error(Errors.HIDDEN_TYPE_PARAMETER, m.position(),
210 "Parameter uses type parameter of unavailable type " + t.fullName() + " in "
211 + cl.qualifiedName() + "." + m.name() + "()");
212 }
213 }
214 }
215 }
216 }
217
218 // annotations are handled like methods
219 for (MethodInfo m : cl.annotationElements()) {
220 if (m.isHiddenOrRemoved()) {
221 Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Reference to unavailable annotation "
222 + m.name());
223 }
224
225 ClassInfo returnClass = m.returnType().asClassInfo();
226 if (returnClass != null && returnClass.isHiddenOrRemoved()) {
227 Errors.error(Errors.UNAVAILABLE_SYMBOL, m.position(), "Annotation '" + m.name()
228 + "' returns unavailable type " + returnClass.name());
229 }
230
231 for (ParameterInfo p : m.parameters()) {
232 TypeInfo t = p.type();
233 if (!t.isPrimitive()) {
234 if (t.asClassInfo().isHiddenOrRemoved()) {
235 Errors.error(Errors.UNAVAILABLE_SYMBOL, p.position(),
236 "Reference to unavailable annotation class " + t.fullName());
237 }
238 }
239 }
240 }
241 } else if (cl.isDeprecated()) {
242 // not hidden, but deprecated
243 Errors.error(Errors.DEPRECATED, cl.position(), "Class " + cl.qualifiedName()
244 + " is deprecated");
245 }
246 }
247
248 // packages contains all the notStrippable classes mapped by their containing packages
249 HashMap<PackageInfo, List<ClassInfo>> packages = new HashMap<PackageInfo, List<ClassInfo>>();
250 final HashSet<Pattern> stubPackageWildcards = extractWildcards(stubPackages);
251 for (ClassInfo cl : notStrippable) {
252 if(cl.containingPackage().name().contains("android.car.xxxx.bt")){
253 System.out.println("=======android.car.xxxx.bt=============continue");
254 continue;
255 }
256 if (!cl.isDocOnly()) {
257 if (stubSourceOnly && !Files.exists(Paths.get(cl.position().file))) {
258 continue;
259 }
260 if (shouldWriteStub(cl.containingPackage().name(), stubPackages, stubPackageWildcards)) {
261 // write out the stubs
262 if (stubsDir != null) {
263 writeClassFile(stubsDir, notStrippable, cl);
264 }
265 // build class list for api file or keep list file
266 if (apiWriter != null || dexApiWriter != null || keepListWriter != null) {
267 if (packages.containsKey(cl.containingPackage())) {
268 packages.get(cl.containingPackage()).add(cl);
269 } else {
270 ArrayList<ClassInfo> classes = new ArrayList<ClassInfo>();
271 classes.add(cl);
272 packages.put(cl.containingPackage(), classes);
273 }
274 }
275 }
276 }
277 }
278
279 if (privateApiWriter != null || privateDexApiWriter != null || removedApiWriter != null
280 || removedDexApiWriter != null) {
281 allClassesByPackage = Converter.allClasses().stream()
282 // Make sure that the files only contains information from the required packages.
283 .filter(ci -> stubPackages == null
284 || stubPackages.contains(ci.containingPackage().qualifiedName()))
285 .collect(Collectors.groupingBy(ClassInfo::containingPackage));
286 }
287
288 final boolean ignoreShown = Doclava.showUnannotated;
289
290 Predicate<MemberInfo> memberIsNotCloned = (x -> !x.isCloned());
291
292 FilterPredicate apiFilter = new FilterPredicate(new ApiPredicate().setIgnoreShown(ignoreShown));
293 ApiPredicate apiReference = new ApiPredicate().setIgnoreShown(true);
294 Predicate<MemberInfo> apiEmit = apiFilter.and(new ElidingPredicate(apiReference));
295 Predicate<MemberInfo> dexApiEmit = memberIsNotCloned.and(apiFilter);
296
297 Predicate<MemberInfo> privateEmit = memberIsNotCloned.and(apiFilter.negate());
298 Predicate<MemberInfo> privateReference = (x -> true);
299
300 FilterPredicate removedFilter =
301 new FilterPredicate(new ApiPredicate().setIgnoreShown(ignoreShown).setMatchRemoved(true));
302 ApiPredicate removedReference = new ApiPredicate().setIgnoreShown(true).setIgnoreRemoved(true);
303 Predicate<MemberInfo> removedEmit = removedFilter.and(new ElidingPredicate(removedReference));
304 Predicate<MemberInfo> removedDexEmit = memberIsNotCloned.and(removedFilter);
305
306 // Write out the current API
307 if (apiWriter != null) {
308 writeApi(apiWriter, packages, apiEmit, apiReference);
309 apiWriter.close();
310 }
311
312 // Write out the current DEX API
313 if (dexApiWriter != null) {
314 writeDexApi(dexApiWriter, packages, dexApiEmit);
315 dexApiWriter.close();
316 }
317
318 // Write out the keep list
319 if (keepListWriter != null) {
320 writeKeepList(keepListWriter, packages, notStrippable);
321 keepListWriter.close();
322 }
323
324 // Write out the private API
325 if (privateApiWriter != null) {
326 writeApi(privateApiWriter, allClassesByPackage, privateEmit, privateReference);
327 privateApiWriter.close();
328 }
329
330 // Write out the private API
331 if (privateDexApiWriter != null) {
332 writeDexApi(privateDexApiWriter, allClassesByPackage, privateEmit);
333 privateDexApiWriter.close();
334 }
335
336 // Write out the removed API
337 if (removedApiWriter != null) {
338 writeApi(removedApiWriter, allClassesByPackage, removedEmit, removedReference);
339 removedApiWriter.close();
340 }
341
342 // Write out the removed DEX API
343 if (removedDexApiWriter != null) {
344 writeDexApi(removedDexApiWriter, allClassesByPackage, removedDexEmit);
345 removedDexApiWriter.close();
346 }
347 }
348
349 private static boolean shouldWriteStub(final String packageName,
350 final HashSet<String> stubPackages, final HashSet<Pattern> stubPackageWildcards) {
351 if (stubPackages == null) {
352 // There aren't any stub packages set, write all stubs
353 return true;
354 }
355 if (stubPackages.contains(packageName)) {
356 // Stub packages contains package, return true
357 return true;
358 }
359 if (stubPackageWildcards != null) {
360 // Else, we will iterate through the wildcards to see if there's a match
361 for (Pattern wildcard : stubPackageWildcards) {
362 if (wildcard.matcher(packageName).matches()) {
363 return true;
364 }
365 }
366 }
367 return false;
368 }
369
370 private static HashSet<Pattern> extractWildcards(HashSet<String> stubPackages) {
371 HashSet<Pattern> wildcards = null;
372 if (stubPackages != null) {
373 for (Iterator<String> i = stubPackages.iterator(); i.hasNext();) {
374 final String pkg = i.next();
375 if (pkg.indexOf('*') != -1) {
376 if (wildcards == null) {
377 wildcards = new HashSet<Pattern>();
378 }
379 // Add the compiled wildcard, replacing * with the regex equivalent
380 wildcards.add(Pattern.compile(pkg.replace("*", ".*?")));
381 // And remove the raw wildcard from the packages
382 i.remove();
383 }
384 }
385 }
386 return wildcards;
387 }
388
389 /**
390 * Find references to hidden classes.
391 *
392 * <p>This finds hidden classes that are used by public parts of the API in order to ensure the
393 * API is self consistent and does not reference classes that are not included in
394 * the stubs. Any such references cause an error to be reported.
395 *
396 * <p>A reference to an imported class is not treated as an error, even though imported classes
397 * are hidden from the stub generation. That is because imported classes are, by definition,
398 * excluded from the set of classes for which stubs are required.
399 *
400 * @param ti the type information to examine for references to hidden classes.
401 * @param stubImportPackages the possibly null set of imported package names.
402 * @return a reference to a hidden class or null if there are none
403 */
404 private static ClassInfo findHiddenClasses(TypeInfo ti, HashSet<String> stubImportPackages) {
405 ClassInfo ci = ti.asClassInfo();
406 if (ci == null) return null;
407 if (stubImportPackages != null
408 && stubImportPackages.contains(ci.containingPackage().qualifiedName())) {
409 return null;
410 }
411 if (ci.isHiddenOrRemoved()) return ci;
412 if (ti.typeArguments() != null) {
413 for (TypeInfo tii : ti.typeArguments()) {
414 // Avoid infinite recursion in the case of Foo<T extends Foo>
415 if (tii.qualifiedTypeName() != ti.qualifiedTypeName()) {
416 ClassInfo hiddenClass = findHiddenClasses(tii, stubImportPackages);
417 if (hiddenClass != null) return hiddenClass;
418 }
419 }
420 }
421 return null;
422 }
423
424 public static void cantStripThis(ClassInfo cl, HashSet<ClassInfo> notStrippable, String why,
425 HashSet<String> stubImportPackages) {
426
427 if (stubImportPackages != null
428 && stubImportPackages.contains(cl.containingPackage().qualifiedName())) {
429 // if the package is imported then it does not need stubbing.
430 return;
431 }
432
433 if (!notStrippable.add(cl)) {
434 // slight optimization: if it already contains cl, it already contains
435 // all of cl's parents
436 return;
437 }
438 cl.setReasonIncluded(why);
439
440 // cant strip annotations
441 /*
442 * if (cl.annotations() != null){ for (AnnotationInstanceInfo ai : cl.annotations()){ if
443 * (ai.type() != null){ cantStripThis(ai.type(), notStrippable, "1:" + cl.qualifiedName()); } }
444 * }
445 */
446 // cant strip any public fields or their generics
447 if (cl.selfFields() != null) {
448 for (FieldInfo fInfo : cl.selfFields()) {
449 if (fInfo.type() != null) {
450 if (fInfo.type().asClassInfo() != null) {
451 cantStripThis(fInfo.type().asClassInfo(), notStrippable, "2:" + cl.qualifiedName(),
452 stubImportPackages);
453 }
454 if (fInfo.type().typeArguments() != null) {
455 for (TypeInfo tTypeInfo : fInfo.type().typeArguments()) {
456 if (tTypeInfo.asClassInfo() != null) {
457 cantStripThis(tTypeInfo.asClassInfo(), notStrippable, "3:" + cl.qualifiedName(),
458 stubImportPackages);
459 }
460 }
461 }
462 }
463 }
464 }
465 // cant strip any of the type's generics
466 if (cl.asTypeInfo() != null) {
467 if (cl.asTypeInfo().typeArguments() != null) {
468 for (TypeInfo tInfo : cl.asTypeInfo().typeArguments()) {
469 if (tInfo.asClassInfo() != null) {
470 cantStripThis(tInfo.asClassInfo(), notStrippable, "4:" + cl.qualifiedName(),
471 stubImportPackages);
472 }
473 }
474 }
475 }
476 // cant strip any of the annotation elements
477 // cantStripThis(cl.annotationElements(), notStrippable);
478 // take care of methods
479 cantStripThis(cl.allSelfMethods(), notStrippable, stubImportPackages);
480 cantStripThis(cl.allConstructors(), notStrippable, stubImportPackages);
481 // blow the outer class open if this is an inner class
482 if (cl.containingClass() != null) {
483 cantStripThis(cl.containingClass(), notStrippable, "5:" + cl.qualifiedName(),
484 stubImportPackages);
485 }
486 // blow open super class and interfaces
487 ClassInfo supr = cl.realSuperclass();
488 if (supr != null) {
489 if (supr.isHiddenOrRemoved()) {
490 // cl is a public class declared as extending a hidden superclass.
491 // this is not a desired practice but it's happened, so we deal
492 // with it by finding the first super class which passes checklevel for purposes of
493 // generating the doc & stub information, and proceeding normally.
494 ClassInfo publicSuper = cl.superclass();
495 cl.init(cl.asTypeInfo(), cl.realInterfaces(), cl.realInterfaceTypes(), cl.innerClasses(),
496 cl.allConstructors(), cl.allSelfMethods(), cl.annotationElements(), cl.allSelfFields(),
497 cl.enumConstants(), cl.containingPackage(), cl.containingClass(),
498 publicSuper, publicSuper.asTypeInfo(), cl.annotations());
499 Errors.error(Errors.HIDDEN_SUPERCLASS, cl.position(), "Public class " + cl.qualifiedName()
500 + " stripped of unavailable superclass " + supr.qualifiedName());
501 } else {
502 cantStripThis(supr, notStrippable, "6:" + cl.realSuperclass().name() + cl.qualifiedName(),
503 stubImportPackages);
504 if (supr.isPrivate()) {
505 Errors.error(Errors.PRIVATE_SUPERCLASS, cl.position(), "Public class "
506 + cl.qualifiedName() + " extends private class " + supr.qualifiedName());
507 }
508 }
509 }
510 }
511
512 private static void cantStripThis(ArrayList<MethodInfo> mInfos, HashSet<ClassInfo> notStrippable,
513 HashSet<String> stubImportPackages) {
514 // for each method, blow open the parameters, throws and return types. also blow open their
515 // generics
516 if (mInfos != null) {
517 for (MethodInfo mInfo : mInfos) {
518 if (mInfo.getTypeParameters() != null) {
519 for (TypeInfo tInfo : mInfo.getTypeParameters()) {
520 if (tInfo.asClassInfo() != null) {
521 cantStripThis(tInfo.asClassInfo(), notStrippable, "8:"
522 + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name(),
523 stubImportPackages);
524 }
525 }
526 }
527 if (mInfo.parameters() != null) {
528 for (ParameterInfo pInfo : mInfo.parameters()) {
529 if (pInfo.type() != null && pInfo.type().asClassInfo() != null) {
530 cantStripThis(pInfo.type().asClassInfo(), notStrippable, "9:"
531 + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name(),
532 stubImportPackages);
533 if (pInfo.type().typeArguments() != null) {
534 for (TypeInfo tInfoType : pInfo.type().typeArguments()) {
535 if (tInfoType.asClassInfo() != null) {
536 ClassInfo tcl = tInfoType.asClassInfo();
537 if (tcl.isHiddenOrRemoved()) {
538 Errors
539 .error(Errors.UNAVAILABLE_SYMBOL, mInfo.position(),
540 "Parameter of hidden type " + tInfoType.fullName() + " in "
541 + mInfo.containingClass().qualifiedName() + '.' + mInfo.name()
542 + "()");
543 } else {
544 cantStripThis(tcl, notStrippable, "10:"
545 + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name(),
546 stubImportPackages);
547 }
548 }
549 }
550 }
551 }
552 }
553 }
554 for (ClassInfo thrown : mInfo.thrownExceptions()) {
555 cantStripThis(thrown, notStrippable, "11:" + mInfo.realContainingClass().qualifiedName()
556 + ":" + mInfo.name(), stubImportPackages);
557 }
558 if (mInfo.returnType() != null && mInfo.returnType().asClassInfo() != null) {
559 cantStripThis(mInfo.returnType().asClassInfo(), notStrippable, "12:"
560 + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name(),
561 stubImportPackages);
562 if (mInfo.returnType().typeArguments() != null) {
563 for (TypeInfo tyInfo : mInfo.returnType().typeArguments()) {
564 if (tyInfo.asClassInfo() != null) {
565 cantStripThis(tyInfo.asClassInfo(), notStrippable, "13:"
566 + mInfo.realContainingClass().qualifiedName() + ":" + mInfo.name(),
567 stubImportPackages);
568 }
569 }
570 }
571 }
572 }
573 }
574 }
575
576 static String javaFileName(ClassInfo cl) {
577 String dir = "";
578 PackageInfo pkg = cl.containingPackage();
579 if (pkg != null) {
580 dir = pkg.name();
581 dir = dir.replace('.', '/') + '/';
582 }
583 return dir + cl.name() + ".java";
584 }
585
586 static void writeClassFile(String stubsDir, HashSet<ClassInfo> notStrippable, ClassInfo cl) {
587 // inner classes are written by their containing class
588 if (cl.containingClass() != null) {
589 return;
590 }
591
592 // Work around the bogus "Array" class we invent for
593 // Arrays.copyOf's Class<? extends T[]> newType parameter. (http://b/2715505)
594 if (cl.containingPackage() != null
595 && cl.containingPackage().name().equals(PackageInfo.DEFAULT_PACKAGE)) {
596 return;
597 }
598
599 String filename = stubsDir + '/' + javaFileName(cl);
600 File file = new File(filename);
601 ClearPage.ensureDirectory(file);
602
603 PrintStream stream = null;
604 try {
605 stream = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
606 writeClassFile(stream, notStrippable, cl);
607 } catch (FileNotFoundException e) {
608 System.err.println("error writing file: " + filename);
609 } finally {
610 if (stream != null) {
611 stream.close();
612 }
613 }
614 }
615
616 static void writeClassFile(PrintStream stream, HashSet<ClassInfo> notStrippable, ClassInfo cl) {
617 PackageInfo pkg = cl.containingPackage();
618 if (cl.containingClass() == null) {
619 stream.print(parseLicenseHeader(cl.position()));
620 }
621 if (pkg != null) {
622 stream.println("package " + pkg.name() + ";");
623 }
624 writeClass(stream, notStrippable, cl);
625 }
626
627 private static String parseLicenseHeader(/* @Nonnull */ SourcePositionInfo positionInfo) {
628 if (positionInfo == null) {
629 throw new NullPointerException("positionInfo == null");
630 }
631
632 try {
633 final File sourceFile = new File(positionInfo.file);
634 if (!sourceFile.exists()) {
635 throw new IllegalArgumentException("Unable to find " + sourceFile +
636 ". This is usually because doclava has been asked to generate stubs for a file " +
637 "that isn't present in the list of input source files but exists in the input " +
638 "classpath.");
639 }
640 return parseLicenseHeader(new FileInputStream(sourceFile));
641 } catch (IOException ioe) {
642 throw new RuntimeException("Unable to parse license header for: " + positionInfo.file, ioe);
643 }
644 }
645
646 /* @VisibleForTesting */
647 static String parseLicenseHeader(InputStream input) throws IOException {
648 StringBuilder builder = new StringBuilder(8192);
649 try (Scanner scanner = new Scanner(
650 new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)))) {
651 String line;
652 while (scanner.hasNextLine()) {
653 line = scanner.nextLine().trim();
654 // Use an extremely simple strategy for parsing license headers : assume that
655 // all file content before the first "package " or "import " directive is a license
656 // header. In some cases this might contain more than just the license header, but we
657 // don't care.
658 if (line.startsWith("package ") || line.startsWith("import ")) {
659 break;
660 }
661 builder.append(line);
662 builder.append("\n");
663 }
664
665 // We've reached the end of the file without reaching any package or import
666 // directives.
667 if (!scanner.hasNextLine()) {
668 throw new IOException("Unable to parse license header");
669 }
670 }
671
672 return builder.toString();
673 }
674
675 static void writeClass(PrintStream stream, HashSet<ClassInfo> notStrippable, ClassInfo cl) {
676 writeAnnotations(stream, cl.annotations(), cl.isDeprecated());
677
678 stream.print(cl.scope() + " ");
679 if (cl.isAbstract() && !cl.isAnnotation() && !cl.isInterface()) {
680 stream.print("abstract ");
681 }
682 if (cl.isStatic()) {
683 stream.print("static ");
684 }
685 if (cl.isFinal() && !cl.isEnum()) {
686 stream.print("final ");
687 }
688 if (false) {
689 stream.print("strictfp ");
690 }
691
692 HashSet<String> classDeclTypeVars = new HashSet();
693 String leafName = cl.asTypeInfo().fullName(classDeclTypeVars);
694 int bracket = leafName.indexOf('<');
695 if (bracket < 0) bracket = leafName.length() - 1;
696 int period = leafName.lastIndexOf('.', bracket);
697 if (period < 0) period = -1;
698 leafName = leafName.substring(period + 1);
699
700 String kind = cl.kind();
701 stream.println(kind + " " + leafName);
702
703 TypeInfo base = cl.superclassType();
704
705 if (!"enum".equals(kind)) {
706 if (base != null && !"java.lang.Object".equals(base.qualifiedTypeName())) {
707 stream.println(" extends " + base.fullName(classDeclTypeVars));
708 }
709 }
710
711 List<TypeInfo> usedInterfaces = new ArrayList<TypeInfo>();
712 for (TypeInfo iface : cl.realInterfaceTypes()) {
713 if (notStrippable.contains(iface.asClassInfo()) && !iface.asClassInfo().isDocOnly()) {
714 usedInterfaces.add(iface);
715 }
716 }
717 if (usedInterfaces.size() > 0 && !cl.isAnnotation()) {
718 // can java annotations extend other ones?
719 if (cl.isInterface() || cl.isAnnotation()) {
720 stream.print(" extends ");
721 } else {
722 stream.print(" implements ");
723 }
724 String comma = "";
725 for (TypeInfo iface : usedInterfaces) {
726 stream.print(comma + iface.fullName(classDeclTypeVars));
727 comma = ", ";
728 }
729 stream.println();
730 }
731
732 stream.println("{");
733
734 ArrayList<FieldInfo> enumConstants = cl.enumConstants();
735 int N = enumConstants.size();
736 int i = 0;
737 for (FieldInfo field : enumConstants) {
738 writeAnnotations(stream, field.annotations(), field.isDeprecated());
739 if (!field.constantLiteralValue().equals("null")) {
740 stream.println(field.name() + "(" + field.constantLiteralValue()
741 + (i == N - 1 ? ");" : "),"));
742 } else {
743 stream.println(field.name() + "(" + (i == N - 1 ? ");" : "),"));
744 }
745 i++;
746 }
747
748 for (ClassInfo inner : cl.getRealInnerClasses()) {
749 if (notStrippable.contains(inner) && !inner.isDocOnly()) {
750 writeClass(stream, notStrippable, inner);
751 }
752 }
753
754
755 for (MethodInfo method : cl.constructors()) {
756 if (!method.isDocOnly()) {
757 writeMethod(stream, method, true);
758 }
759 }
760
761 boolean fieldNeedsInitialization = false;
762 boolean staticFieldNeedsInitialization = false;
763 for (FieldInfo field : cl.selfFields()) {
764 if (!field.isDocOnly()) {
765 if (!field.isStatic() && field.isFinal() && !fieldIsInitialized(field)) {
766 fieldNeedsInitialization = true;
767 }
768 if (field.isStatic() && field.isFinal() && !fieldIsInitialized(field)) {
769 staticFieldNeedsInitialization = true;
770 }
771 }
772 }
773
774 // The compiler includes a default public constructor that calls the super classes
775 // default constructor in the case where there are no written constructors.
776 // So, if we hide all the constructors, java may put in a constructor
777 // that calls a nonexistent super class constructor. So, if there are no constructors,
778 // and the super class doesn't have a default constructor, write in a private constructor
779 // that works. TODO -- we generate this as protected, but we really should generate
780 // it as private unless it also exists in the real code.
781 if ((cl.constructors().isEmpty() && (!cl.getNonWrittenConstructors().isEmpty() ||
782 fieldNeedsInitialization)) && !cl.isAnnotation() && !cl.isInterface() && !cl.isEnum()) {
783 // Errors.error(Errors.HIDDEN_CONSTRUCTOR,
784 // cl.position(), "No constructors " +
785 // "found and superclass has no parameterless constructor. A constructor " +
786 // "that calls an appropriate superclass constructor " +
787 // "was automatically written to stubs.\n");
788 stream.println(cl.leafName() + "() { " + superCtorCall(cl, null) + "throw new"
789 + " RuntimeException(\"Stub!\"); }");
790 }
791
792 for (MethodInfo method : cl.allSelfMethods()) {
793 if (cl.isEnum()) {
794 if (("values".equals(method.name()) && "()".equals(method.signature())) ||
795 ("valueOf".equals(method.name()) &&
796 "(java.lang.String)".equals(method.signature()))) {
797 // skip these two methods on enums, because they're synthetic,
798 // although for some reason javadoc doesn't mark them as synthetic,
799 // maybe because they still want them documented
800 continue;
801 }
802 }
803 if (!method.isDocOnly()) {
804 writeMethod(stream, method, false);
805 }
806 }
807 // Write all methods that are hidden or removed, but override abstract methods or interface methods.
808 // These can't be hidden.
809 List<MethodInfo> hiddenAndRemovedMethods = cl.getHiddenMethods();
810 hiddenAndRemovedMethods.addAll(cl.getRemovedMethods());
811 for (MethodInfo method : hiddenAndRemovedMethods) {
812 MethodInfo overriddenMethod =
813 method.findRealOverriddenMethod(method.name(), method.signature(), notStrippable);
814 ClassInfo classContainingMethod =
815 method.findRealOverriddenClass(method.name(), method.signature());
816 if (overriddenMethod != null && !overriddenMethod.isHiddenOrRemoved() &&
817 !overriddenMethod.isDocOnly() &&
818 (overriddenMethod.isAbstract() || overriddenMethod.containingClass().isInterface())) {
819 method.setReason("1:" + classContainingMethod.qualifiedName());
820 cl.addMethod(method);
821 writeMethod(stream, method, false);
822 }
823 }
824
825 for (MethodInfo element : cl.annotationElements()) {
826 if (!element.isDocOnly()) {
827 writeAnnotationElement(stream, element);
828 }
829 }
830
831 for (FieldInfo field : cl.selfFields()) {
832 if (!field.isDocOnly()) {
833 writeField(stream, field);
834 }
835 }
836
837 if (staticFieldNeedsInitialization) {
838 stream.print("static { ");
839 for (FieldInfo field : cl.selfFields()) {
840 if (!field.isDocOnly() && field.isStatic() && field.isFinal() && !fieldIsInitialized(field)
841 && field.constantValue() == null) {
842 stream.print(field.name() + " = " + field.type().defaultValue() + "; ");
843 }
844 }
845 stream.println("}");
846 }
847
848 stream.println("}");
849 }
850
851 static void writeMethod(PrintStream stream, MethodInfo method, boolean isConstructor) {
852 String comma;
853
854 writeAnnotations(stream, method.annotations(), method.isDeprecated());
855
856 if (method.isDefault()) {
857 stream.print("default ");
858 }
859 stream.print(method.scope() + " ");
860 if (method.isStatic()) {
861 stream.print("static ");
862 }
863 if (method.isFinal()) {
864 stream.print("final ");
865 }
866 if (method.isAbstract()) {
867 stream.print("abstract ");
868 }
869 if (method.isSynchronized()) {
870 stream.print("synchronized ");
871 }
872 if (method.isNative()) {
873 stream.print("native ");
874 }
875 if (false /* method.isStictFP() */) {
876 stream.print("strictfp ");
877 }
878
879 stream.print(method.typeArgumentsName(new HashSet()) + " ");
880
881 if (!isConstructor) {
882 stream.print(method.returnType().fullName(method.typeVariables()) + " ");
883 }
884 String n = method.name();
885 int pos = n.lastIndexOf('.');
886 if (pos >= 0) {
887 n = n.substring(pos + 1);
888 }
889 stream.print(n + "(");
890 comma = "";
891 int count = 1;
892 int size = method.parameters().size();
893 for (ParameterInfo param : method.parameters()) {
894 stream.print(comma);
895 writeAnnotations(stream, param.annotations(), false);
896 stream.print(fullParameterTypeName(method, param.type(), count == size) + " "
897 + param.name());
898 comma = ", ";
899 count++;
900 }
901 stream.print(")");
902
903 comma = "";
904 if (method.thrownExceptions().size() > 0) {
905 stream.print(" throws ");
906 for (ClassInfo thrown : method.thrownExceptions()) {
907 stream.print(comma + thrown.qualifiedName());
908 comma = ", ";
909 }
910 }
911 if (method.isAbstract() || method.isNative() || (method.containingClass().isInterface() && (!method.isDefault() && !method.isStatic()))) {
912 stream.println(";");
913 } else {
914 stream.print(" { ");
915 if (isConstructor) {
916 stream.print(superCtorCall(method.containingClass(), method.thrownExceptions()));
917 }
918 stream.println("throw new RuntimeException(\"Stub!\"); }");
919 }
920 }
921
922 static void writeField(PrintStream stream, FieldInfo field) {
923 writeAnnotations(stream, field.annotations(), field.isDeprecated());
924
925 stream.print(field.scope() + " ");
926 if (field.isStatic()) {
927 stream.print("static ");
928 }
929 if (field.isFinal()) {
930 stream.print("final ");
931 }
932 if (field.isTransient()) {
933 stream.print("transient ");
934 }
935 if (field.isVolatile()) {
936 stream.print("volatile ");
937 }
938
939 stream.print(field.type().fullName());
940 stream.print(" ");
941 stream.print(field.name());
942
943 if (fieldIsInitialized(field)) {
944 stream.print(" = " + field.constantLiteralValue());
945 }
946
947 stream.println(";");
948 }
949
950 static boolean fieldIsInitialized(FieldInfo field) {
951 return (field.isFinal() && field.constantValue() != null)
952 || !field.type().dimension().equals("") || field.containingClass().isInterface();
953 }
954
955 static boolean canCallMethod(ClassInfo from, MethodInfo m) {
956 if (m.isPublic() || m.isProtected()) {
957 return true;
958 }
959 if (m.isPackagePrivate()) {
960 String fromPkg = from.containingPackage().name();
961 String pkg = m.containingClass().containingPackage().name();
962 if (fromPkg.equals(pkg)) {
963 return true;
964 }
965 }
966 return false;
967 }
968
969 // call a constructor, any constructor on this class's superclass.
970 static String superCtorCall(ClassInfo cl, ArrayList<ClassInfo> thrownExceptions) {
971 ClassInfo base = cl.realSuperclass();
972 if (base == null) {
973 return "";
974 }
975 HashSet<String> exceptionNames = new HashSet<String>();
976 if (thrownExceptions != null) {
977 for (ClassInfo thrown : thrownExceptions) {
978 exceptionNames.add(thrown.name());
979 }
980 }
981 ArrayList<MethodInfo> ctors = base.constructors();
982 MethodInfo ctor = null;
983 // bad exception indicates that the exceptions thrown by the super constructor
984 // are incompatible with the constructor we're using for the sub class.
985 Boolean badException = false;
986 for (MethodInfo m : ctors) {
987 if (canCallMethod(cl, m)) {
988 if (m.thrownExceptions() != null) {
989 for (ClassInfo thrown : m.thrownExceptions()) {
990 if (thrownExceptions != null && !exceptionNames.contains(thrown.name())) {
991 badException = true;
992 }
993 }
994 }
995 if (badException) {
996 badException = false;
997 continue;
998 }
999 // if it has no args, we're done
1000 if (m.parameters().isEmpty()) {
1001 return "";
1002 }
1003 ctor = m;
1004 }
1005 }
1006 if (ctor != null) {
1007 String result = "";
1008 result += "super(";
1009 ArrayList<ParameterInfo> params = ctor.parameters();
1010 for (ParameterInfo param : params) {
1011 TypeInfo t = param.type();
1012 if (t.isPrimitive() && t.dimension().equals("")) {
1013 String n = t.simpleTypeName();
1014 if (("byte".equals(n) || "short".equals(n) || "int".equals(n) || "long".equals(n)
1015 || "float".equals(n) || "double".equals(n))
1016 && t.dimension().equals("")) {
1017 result += "0";
1018 } else if ("char".equals(n)) {
1019 result += "'\\0'";
1020 } else if ("boolean".equals(n)) {
1021 result += "false";
1022 } else {
1023 result += "<<unknown-" + n + ">>";
1024 }
1025 } else {
1026 // put null in each super class method. Cast null to the correct type
1027 // to avoid collisions with other constructors. If the type is generic
1028 // don't cast it
1029 result +=
1030 (!t.isTypeVariable() ? "(" + t.qualifiedTypeName() + t.dimension() + ")" : "")
1031 + "null";
1032 }
1033 if (param != params.get(params.size()-1)) {
1034 result += ",";
1035 }
1036 }
1037 result += "); ";
1038 return result;
1039 } else {
1040 return "";
1041 }
1042 }
1043
1044 /**
1045 * Write out the given list of annotations. If the {@code isDeprecated}
1046 * flag is true also write out a {@code @Deprecated} annotation if it did not
1047 * already appear in the list of annotations. (This covers APIs that mention
1048 * {@code @deprecated} in their documentation but fail to add
1049 * {@code @Deprecated} as an annotation.
1050 * <p>
1051 * {@code @Override} annotations are deliberately skipped.
1052 */
1053 static void writeAnnotations(PrintStream stream, List<AnnotationInstanceInfo> annotations,
1054 boolean isDeprecated) {
1055 assert annotations != null;
1056 for (AnnotationInstanceInfo ann : annotations) {
1057 // Skip @Override annotations: the stubs do not need it and in some cases it leads
1058 // to compilation errors with the way the stubs are generated
1059 if (ann.type() != null && ann.type().qualifiedName().equals("java.lang.Override")) {
1060 continue;
1061 }
1062 if (!ann.type().isHiddenOrRemoved()) {
1063 stream.println(ann.toString());
1064 if (isDeprecated && ann.type() != null
1065 && ann.type().qualifiedName().equals("java.lang.Deprecated")) {
1066 isDeprecated = false; // Prevent duplicate annotations
1067 }
1068 }
1069 }
1070 if (isDeprecated) {
1071 stream.println("@Deprecated");
1072 }
1073 }
1074
1075 static void writeAnnotationElement(PrintStream stream, MethodInfo ann) {
1076 stream.print(ann.returnType().fullName());
1077 stream.print(" ");
1078 stream.print(ann.name());
1079 stream.print("()");
1080 AnnotationValueInfo def = ann.defaultAnnotationElementValue();
1081 if (def != null) {
1082 stream.print(" default ");
1083 stream.print(def.valueString());
1084 }
1085 stream.println(";");
1086 }
1087
1088 public static void writeXml(PrintStream xmlWriter, Collection<PackageInfo> pkgs, boolean strip) {
1089 if (strip) {
1090 Stubs.writeXml(xmlWriter, pkgs);
1091 } else {
1092 Stubs.writeXml(xmlWriter, pkgs, c -> true);
1093 }
1094 }
1095
1096 public static void writeXml(PrintStream xmlWriter, Collection<PackageInfo> pkgs,
1097 Predicate<ClassInfo> notStrippable) {
1098
1099 final PackageInfo[] packages = pkgs.toArray(new PackageInfo[pkgs.size()]);
1100 Arrays.sort(packages, PackageInfo.comparator);
1101
1102 xmlWriter.println("<api>");
1103 for (PackageInfo pkg: packages) {
1104 writePackageXML(xmlWriter, pkg, pkg.allClasses().values(), notStrippable);
1105 }
1106 xmlWriter.println("</api>");
1107 }
1108
1109 public static void writeXml(PrintStream xmlWriter, Collection<PackageInfo> pkgs) {
1110 HashSet<ClassInfo> allClasses = new HashSet<>();
1111 for (PackageInfo pkg: pkgs) {
1112 allClasses.addAll(pkg.allClasses().values());
1113 }
1114 Predicate<ClassInfo> notStrippable = allClasses::contains;
1115 writeXml(xmlWriter, pkgs, notStrippable);
1116 }
1117
1118 static void writePackageXML(PrintStream xmlWriter, PackageInfo pack,
1119 Collection<ClassInfo> classList, Predicate<ClassInfo> notStrippable) {
1120 ClassInfo[] classes = classList.toArray(new ClassInfo[classList.size()]);
1121 Arrays.sort(classes, ClassInfo.comparator);
1122 // Work around the bogus "Array" class we invent for
1123 // Arrays.copyOf's Class<? extends T[]> newType parameter. (http://b/2715505)
1124 if (pack.name().equals(PackageInfo.DEFAULT_PACKAGE)) {
1125 return;
1126 }
1127 xmlWriter.println("<package name=\"" + pack.name() + "\"\n"
1128 // + " source=\"" + pack.position() + "\"\n"
1129 + ">");
1130 for (ClassInfo cl : classes) {
1131 writeClassXML(xmlWriter, cl, notStrippable);
1132 }
1133 xmlWriter.println("</package>");
1134
1135
1136 }
1137
1138 static void writeClassXML(PrintStream xmlWriter, ClassInfo cl, Predicate<ClassInfo> notStrippable) {
1139 String scope = cl.scope();
1140 String deprecatedString = "";
1141 String declString = (cl.isInterface()) ? "interface" : "class";
1142 if (cl.isDeprecated()) {
1143 deprecatedString = "deprecated";
1144 } else {
1145 deprecatedString = "not deprecated";
1146 }
1147 xmlWriter.println("<" + declString + " name=\"" + cl.name() + "\"");
1148 if (!cl.isInterface() && !cl.qualifiedName().equals("java.lang.Object")) {
1149 xmlWriter.println(" extends=\""
1150 + ((cl.realSuperclass() == null) ? "java.lang.Object" : cl.realSuperclass()
1151 .qualifiedName()) + "\"");
1152 }
1153 xmlWriter.println(" abstract=\"" + cl.isAbstract() + "\"\n" + " static=\"" + cl.isStatic()
1154 + "\"\n" + " final=\"" + cl.isFinal() + "\"\n" + " deprecated=\"" + deprecatedString
1155 + "\"\n" + " visibility=\"" + scope + "\"\n"
1156 // + " source=\"" + cl.position() + "\"\n"
1157 + ">");
1158
1159 ArrayList<ClassInfo> interfaces = cl.realInterfaces();
1160 Collections.sort(interfaces, ClassInfo.comparator);
1161 for (ClassInfo iface : interfaces) {
1162 if (notStrippable.test(iface)) {
1163 xmlWriter.println("<implements name=\"" + iface.qualifiedName() + "\">");
1164 xmlWriter.println("</implements>");
1165 }
1166 }
1167
1168 ArrayList<MethodInfo> constructors = cl.constructors();
1169 Collections.sort(constructors, MethodInfo.comparator);
1170 for (MethodInfo mi : constructors) {
1171 writeConstructorXML(xmlWriter, mi);
1172 }
1173
1174 ArrayList<MethodInfo> methods = cl.allSelfMethods();
1175 Collections.sort(methods, MethodInfo.comparator);
1176 for (MethodInfo mi : methods) {
1177 writeMethodXML(xmlWriter, mi);
1178 }
1179
1180 ArrayList<FieldInfo> fields = cl.selfFields();
1181 Collections.sort(fields, FieldInfo.comparator);
1182 for (FieldInfo fi : fields) {
1183 writeFieldXML(xmlWriter, fi);
1184 }
1185 xmlWriter.println("</" + declString + ">");
1186
1187 }
1188
1189 static void writeMethodXML(PrintStream xmlWriter, MethodInfo mi) {
1190 String scope = mi.scope();
1191
1192 String deprecatedString = "";
1193 if (mi.isDeprecated()) {
1194 deprecatedString = "deprecated";
1195 } else {
1196 deprecatedString = "not deprecated";
1197 }
1198 xmlWriter.println("<method name=\""
1199 + mi.name()
1200 + "\"\n"
1201 + ((mi.returnType() != null) ? " return=\""
1202 + makeXMLcompliant(fullParameterTypeName(mi, mi.returnType(), false)) + "\"\n" : "")
1203 + " abstract=\"" + mi.isAbstract() + "\"\n" + " native=\"" + mi.isNative() + "\"\n"
1204 + " synchronized=\"" + mi.isSynchronized() + "\"\n" + " static=\"" + mi.isStatic() + "\"\n"
1205 + " final=\"" + mi.isFinal() + "\"\n" + " deprecated=\"" + deprecatedString + "\"\n"
1206 + " visibility=\"" + scope + "\"\n"
1207 // + " source=\"" + mi.position() + "\"\n"
1208 + ">");
1209
1210 // write parameters in declaration order
1211 int numParameters = mi.parameters().size();
1212 int count = 0;
1213 for (ParameterInfo pi : mi.parameters()) {
1214 count++;
1215 writeParameterXML(xmlWriter, mi, pi, count == numParameters);
1216 }
1217
1218 // but write exceptions in canonicalized order
1219 ArrayList<ClassInfo> exceptions = mi.thrownExceptions();
1220 Collections.sort(exceptions, ClassInfo.comparator);
1221 for (ClassInfo pi : exceptions) {
1222 xmlWriter.println("<exception name=\"" + pi.name() + "\" type=\"" + pi.qualifiedName()
1223 + "\">");
1224 xmlWriter.println("</exception>");
1225 }
1226 xmlWriter.println("</method>");
1227 }
1228
1229 static void writeConstructorXML(PrintStream xmlWriter, MethodInfo mi) {
1230 String scope = mi.scope();
1231 String deprecatedString = "";
1232 if (mi.isDeprecated()) {
1233 deprecatedString = "deprecated";
1234 } else {
1235 deprecatedString = "not deprecated";
1236 }
1237 xmlWriter.println("<constructor name=\"" + mi.name() + "\"\n" + " type=\""
1238 + mi.containingClass().qualifiedName() + "\"\n" + " static=\"" + mi.isStatic() + "\"\n"
1239 + " final=\"" + mi.isFinal() + "\"\n" + " deprecated=\"" + deprecatedString + "\"\n"
1240 + " visibility=\"" + scope + "\"\n"
1241 // + " source=\"" + mi.position() + "\"\n"
1242 + ">");
1243
1244 int numParameters = mi.parameters().size();
1245 int count = 0;
1246 for (ParameterInfo pi : mi.parameters()) {
1247 count++;
1248 writeParameterXML(xmlWriter, mi, pi, count == numParameters);
1249 }
1250
1251 ArrayList<ClassInfo> exceptions = mi.thrownExceptions();
1252 Collections.sort(exceptions, ClassInfo.comparator);
1253 for (ClassInfo pi : exceptions) {
1254 xmlWriter.println("<exception name=\"" + pi.name() + "\" type=\"" + pi.qualifiedName()
1255 + "\">");
1256 xmlWriter.println("</exception>");
1257 }
1258 xmlWriter.println("</constructor>");
1259 }
1260
1261 static void writeParameterXML(PrintStream xmlWriter, MethodInfo method, ParameterInfo pi,
1262 boolean isLast) {
1263 xmlWriter.println("<parameter name=\"" + pi.name() + "\" type=\""
1264 + makeXMLcompliant(fullParameterTypeName(method, pi.type(), isLast)) + "\">");
1265 xmlWriter.println("</parameter>");
1266 }
1267
1268 static void writeFieldXML(PrintStream xmlWriter, FieldInfo fi) {
1269 String scope = fi.scope();
1270 String deprecatedString = "";
1271 if (fi.isDeprecated()) {
1272 deprecatedString = "deprecated";
1273 } else {
1274 deprecatedString = "not deprecated";
1275 }
1276 // need to make sure value is valid XML
1277 String value = makeXMLcompliant(fi.constantLiteralValue());
1278
1279 String fullTypeName = makeXMLcompliant(fi.type().fullName());
1280
1281 xmlWriter.println("<field name=\"" + fi.name() + "\"\n" + " type=\"" + fullTypeName + "\"\n"
1282 + " transient=\"" + fi.isTransient() + "\"\n" + " volatile=\"" + fi.isVolatile() + "\"\n"
1283 + (fieldIsInitialized(fi) ? " value=\"" + value + "\"\n" : "") + " static=\""
1284 + fi.isStatic() + "\"\n" + " final=\"" + fi.isFinal() + "\"\n" + " deprecated=\""
1285 + deprecatedString + "\"\n" + " visibility=\"" + scope + "\"\n"
1286 // + " source=\"" + fi.position() + "\"\n"
1287 + ">");
1288 xmlWriter.println("</field>");
1289 }
1290
1291 static String makeXMLcompliant(String s) {
1292 String returnString = "";
1293 returnString = s.replaceAll("&", "&");
1294 returnString = returnString.replaceAll("<", "<");
1295 returnString = returnString.replaceAll(">", ">");
1296 returnString = returnString.replaceAll("\"", """);
1297 returnString = returnString.replaceAll("'", "'");
1298 return returnString;
1299 }
1300
1301 /**
1302 * Predicate that decides if the given member should be considered part of an
1303 * API surface area. To make the most accurate decision, it searches for
1304 * signals on the member, all containing classes, and all containing packages.
1305 */
1306 public static class ApiPredicate implements Predicate<MemberInfo> {
1307 public boolean ignoreShown;
1308 public boolean ignoreRemoved;
1309 public boolean matchRemoved;
1310
1311 /**
1312 * Set if the value of {@link MemberInfo#hasShowAnnotation()} should be
1313 * ignored. That is, this predicate will assume that all encountered members
1314 * match the "shown" requirement.
1315 * <p>
1316 * This is typically useful when generating "current.txt", when no
1317 * {@link Doclava#showAnnotations} have been defined.
1318 */
1319 public ApiPredicate setIgnoreShown(boolean ignoreShown) {
1320 this.ignoreShown = ignoreShown;
1321 return this;
1322 }
1323
1324 /**
1325 * Set if the value of {@link MemberInfo#isRemoved()} should be ignored.
1326 * That is, this predicate will assume that all encountered members match
1327 * the "removed" requirement.
1328 * <p>
1329 * This is typically useful when generating "removed.txt", when it's okay to
1330 * reference both current and removed APIs.
1331 */
1332 public ApiPredicate setIgnoreRemoved(boolean ignoreRemoved) {
1333 this.ignoreRemoved = ignoreRemoved;
1334 return this;
1335 }
1336
1337 /**
1338 * Set what the value of {@link MemberInfo#isRemoved()} must be equal to in
1339 * order for a member to match.
1340 * <p>
1341 * This is typically useful when generating "removed.txt", when you only
1342 * want to match members that have actually been removed.
1343 */
1344 public ApiPredicate setMatchRemoved(boolean matchRemoved) {
1345 this.matchRemoved = matchRemoved;
1346 return this;
1347 }
1348
1349 private static PackageInfo containingPackage(PackageInfo pkg) {
1350 String name = pkg.name();
1351 final int lastDot = name.lastIndexOf('.');
1352 if (lastDot == -1) {
1353 return null;
1354 } else {
1355 name = name.substring(0, lastDot);
1356 return Converter.obtainPackage(name);
1357 }
1358 }
1359
1360 @Override
1361 public boolean test(MemberInfo member) {
1362 boolean visible = member.isPublic() || member.isProtected();
1363 boolean hasShowAnnotation = member.hasShowAnnotation();
1364 boolean hidden = member.isHidden();
1365 boolean docOnly = member.isDocOnly();
1366 boolean removed = member.isRemoved();
1367
1368 ClassInfo clazz = member.containingClass();
1369 if (clazz != null) {
1370 PackageInfo pkg = clazz.containingPackage();
1371 while (pkg != null) {
1372 hidden |= pkg.isHidden();
1373 docOnly |= pkg.isDocOnly();
1374 removed |= pkg.isRemoved();
1375 pkg = containingPackage(pkg);
1376 }
1377 }
1378 while (clazz != null) {
1379 visible &= clazz.isPublic() || clazz.isProtected();
1380 hasShowAnnotation |= clazz.hasShowAnnotation();
1381 hidden |= clazz.isHidden();
1382 docOnly |= clazz.isDocOnly();
1383 removed |= clazz.isRemoved();
1384 clazz = clazz.containingClass();
1385 }
1386
1387 if (ignoreShown) {
1388 hasShowAnnotation = true;
1389 }
1390 if (ignoreRemoved) {
1391 removed = matchRemoved;
1392 }
1393
1394 return visible && hasShowAnnotation && !hidden && !docOnly && (removed == matchRemoved);
1395 }
1396 }
1397
1398 /**
1399 * Filter that will elide exact duplicate members that are already included
1400 * in another superclass/interfaces.
1401 */
1402 public static class ElidingPredicate implements Predicate<MemberInfo> {
1403 private final Predicate<MemberInfo> wrapped;
1404
1405 public ElidingPredicate(Predicate<MemberInfo> wrapped) {
1406 this.wrapped = wrapped;
1407 }
1408
1409 @Override
1410 public boolean test(MemberInfo member) {
1411 // This member should be included, but if it's an exact duplicate
1412 // override then we can elide it.
1413 if (member instanceof MethodInfo) {
1414 MethodInfo method = (MethodInfo) member;
1415 if (method.returnType() != null) { // not a constructor
1416 String methodRaw = writeMethodApiWithoutDefault(method);
1417 return (method.findPredicateOverriddenMethod(new Predicate<MemberInfo>() {
1418 @Override
1419 public boolean test(MemberInfo test) {
1420 // We're looking for included and perfect signature
1421 return (wrapped.test(test)
1422 && writeMethodApiWithoutDefault((MethodInfo) test).equals(methodRaw));
1423 }
1424 }) == null);
1425 }
1426 }
1427 return true;
1428 }
1429 }
1430
1431 public static class FilterPredicate implements Predicate<MemberInfo> {
1432 private final Predicate<MemberInfo> wrapped;
1433
1434 public FilterPredicate(Predicate<MemberInfo> wrapped) {
1435 this.wrapped = wrapped;
1436 }
1437
1438 @Override
1439 public boolean test(MemberInfo member) {
1440 if (wrapped.test(member)) {
1441 return true;
1442 } else if (member instanceof MethodInfo) {
1443 MethodInfo method = (MethodInfo) member;
1444 return method.returnType() != null && // not a constructor
1445 method.findPredicateOverriddenMethod(wrapped) != null;
1446 } else {
1447 return false;
1448 }
1449 }
1450 }
1451
1452 static void writeApi(PrintStream apiWriter, Map<PackageInfo, List<ClassInfo>> classesByPackage,
1453 Predicate<MemberInfo> filterEmit, Predicate<MemberInfo> filterReference) {
1454 for (PackageInfo pkg : classesByPackage.keySet().stream().sorted(PackageInfo.comparator)
1455 .collect(Collectors.toList())) {
1456 if (pkg.name().equals(PackageInfo.DEFAULT_PACKAGE)) continue;
1457
1458 boolean hasWrittenPackageHead = false;
1459 for (ClassInfo clazz : classesByPackage.get(pkg).stream().sorted(ClassInfo.comparator)
1460 .collect(Collectors.toList())) {
1461 hasWrittenPackageHead = writeClassApi(apiWriter, clazz, filterEmit, filterReference,
1462 hasWrittenPackageHead);
1463 }
1464
1465 if (hasWrittenPackageHead) {
1466 apiWriter.print("}\n\n");
1467 }
1468 }
1469 }
1470
1471 static void writeDexApi(PrintStream apiWriter, Map<PackageInfo, List<ClassInfo>> classesByPackage,
1472 Predicate<MemberInfo> filterEmit) {
1473 for (PackageInfo pkg : classesByPackage.keySet().stream().sorted(PackageInfo.comparator)
1474 .collect(Collectors.toList())) {
1475 if (pkg.name().equals(PackageInfo.DEFAULT_PACKAGE)) continue;
1476
1477 for (ClassInfo clazz : classesByPackage.get(pkg).stream().sorted(ClassInfo.comparator)
1478 .collect(Collectors.toList())) {
1479 writeClassDexApi(apiWriter, clazz, filterEmit);
1480 }
1481 }
1482 }
1483
1484 /**
1485 * Write the removed members of the class to removed.txt
1486 */
1487 private static boolean writeClassApi(PrintStream apiWriter, ClassInfo cl,
1488 Predicate<MemberInfo> filterEmit, Predicate<MemberInfo> filterReference,
1489 boolean hasWrittenPackageHead) {
1490
1491 List<MethodInfo> constructors = cl.getExhaustiveConstructors().stream().filter(filterEmit)
1492 .sorted(MethodInfo.comparator).collect(Collectors.toList());
1493 List<MethodInfo> methods = cl.getExhaustiveMethods().stream().filter(filterEmit)
1494 .sorted(MethodInfo.comparator).collect(Collectors.toList());
1495 List<FieldInfo> enums = cl.getExhaustiveEnumConstants().stream().filter(filterEmit)
1496 .sorted(FieldInfo.comparator).collect(Collectors.toList());
1497 List<FieldInfo> fields = cl.filteredFields(filterEmit).stream()
1498 .sorted(FieldInfo.comparator).collect(Collectors.toList());
1499
1500 final boolean classEmpty = (constructors.isEmpty() && methods.isEmpty() && enums.isEmpty()
1501 && fields.isEmpty());
1502 final boolean emit;
1503 if (filterEmit.test(cl.asMemberInfo())) {
1504 emit = true;
1505 } else if (!classEmpty) {
1506 emit = filterReference.test(cl.asMemberInfo());
1507 } else {
1508 emit = false;
1509 }
1510 if (!emit) {
1511 return hasWrittenPackageHead;
1512 }
1513
1514 // Look for Android @SystemApi exposed outside the normal SDK; we require
1515 // that they're protected with a system permission.
1516 if (Doclava.android && Doclava.showAnnotations.contains("android.annotation.SystemApi")) {
1517 boolean systemService = "android.content.pm.PackageManager".equals(cl.qualifiedName());
1518 for (AnnotationInstanceInfo a : cl.annotations()) {
1519 if (a.type().qualifiedNameMatches("android", "annotation.SystemService")) {
1520 systemService = true;
1521 }
1522 }
1523 if (systemService) {
1524 for (MethodInfo mi : methods) {
1525 checkSystemPermissions(mi);
1526 }
1527 }
1528 }
1529
1530 for (MethodInfo method : methods) {
1531 checkHiddenTypes(method, filterReference);
1532 }
1533 for (FieldInfo field : fields) {
1534 checkHiddenTypes(field, filterReference);
1535 }
1536
1537 if (!hasWrittenPackageHead) {
1538 hasWrittenPackageHead = true;
1539 apiWriter.print("package ");
1540 apiWriter.print(cl.containingPackage().qualifiedName());
1541 apiWriter.print(" {\n\n");
1542 }
1543
1544 apiWriter.print(" ");
1545 apiWriter.print(cl.scope());
1546 if (cl.isStatic()) {
1547 apiWriter.print(" static");
1548 }
1549 if (cl.isFinal()) {
1550 apiWriter.print(" final");
1551 }
1552 if (cl.isAbstract()) {
1553 apiWriter.print(" abstract");
1554 }
1555 if (cl.isDeprecated()) {
1556 apiWriter.print(" deprecated");
1557 }
1558 apiWriter.print(" ");
1559 apiWriter.print(cl.isInterface() ? "interface" : "class");
1560 apiWriter.print(" ");
1561 apiWriter.print(cl.name());
1562 if (cl.hasTypeParameters()) {
1563 apiWriter.print(TypeInfo.typeArgumentsName(cl.asTypeInfo().typeArguments(),
1564 new HashSet<String>()));
1565 }
1566
1567 if (!cl.isInterface()
1568 && !"java.lang.Object".equals(cl.qualifiedName())) {
1569 final ClassInfo superclass = cl.filteredSuperclass(filterReference);
1570 if (superclass != null && !"java.lang.Object".equals(superclass.qualifiedName())) {
1571 apiWriter.print(" extends ");
1572 apiWriter.print(superclass.qualifiedName());
1573 }
1574 }
1575
1576 List<ClassInfo> interfaces = cl.filteredInterfaces(filterReference).stream()
1577 .sorted(ClassInfo.comparator).collect(Collectors.toList());
1578 boolean first = true;
1579 for (ClassInfo iface : interfaces) {
1580 if (first) {
1581 apiWriter.print(" implements");
1582 first = false;
1583 }
1584 apiWriter.print(" ");
1585 apiWriter.print(iface.qualifiedName());
1586 }
1587
1588 apiWriter.print(" {\n");
1589
1590 for (MethodInfo mi : constructors) {
1591 writeConstructorApi(apiWriter, mi);
1592 }
1593 for (MethodInfo mi : methods) {
1594 writeMethodApi(apiWriter, mi);
1595 }
1596 for (FieldInfo fi : enums) {
1597 writeFieldApi(apiWriter, fi, "enum_constant");
1598 }
1599 for (FieldInfo fi : fields) {
1600 writeFieldApi(apiWriter, fi, "field");
1601 }
1602
1603 apiWriter.print(" }\n\n");
1604 return hasWrittenPackageHead;
1605 }
1606
1607 private static void writeClassDexApi(PrintStream apiWriter, ClassInfo cl,
1608 Predicate<MemberInfo> filterEmit) {
1609 if (filterEmit.test(cl.asMemberInfo())) {
1610 apiWriter.print(toSlashFormat(cl.qualifiedName()));
1611 apiWriter.print("\n");
1612 }
1613
1614 List<MethodInfo> constructors = cl.getExhaustiveConstructors().stream().filter(filterEmit)
1615 .sorted(MethodInfo.comparator).collect(Collectors.toList());
1616 List<MethodInfo> methods = cl.getExhaustiveMethods().stream().filter(filterEmit)
1617 .sorted(MethodInfo.comparator).collect(Collectors.toList());
1618 List<FieldInfo> enums = cl.getExhaustiveEnumConstants().stream().filter(filterEmit)
1619 .sorted(FieldInfo.comparator).collect(Collectors.toList());
1620 List<FieldInfo> fields = cl.getExhaustiveFields().stream().filter(filterEmit)
1621 .sorted(FieldInfo.comparator).collect(Collectors.toList());
1622
1623 for (MethodInfo mi : constructors) {
1624 writeMethodDexApi(apiWriter, cl, mi);
1625 }
1626 for (MethodInfo mi : methods) {
1627 writeMethodDexApi(apiWriter, cl, mi);
1628 }
1629 for (FieldInfo fi : enums) {
1630 writeFieldDexApi(apiWriter, cl, fi);
1631 }
1632 for (FieldInfo fi : fields) {
1633 writeFieldDexApi(apiWriter, cl, fi);
1634 }
1635 }
1636
1637 private static void checkSystemPermissions(MethodInfo mi) {
1638 boolean hasAnnotation = false;
1639 for (AnnotationInstanceInfo a : mi.annotations()) {
1640 if (a.type().qualifiedNameMatches("android", "annotation.RequiresPermission")) {
1641 hasAnnotation = true;
1642 for (AnnotationValueInfo val : a.elementValues()) {
1643 ArrayList<AnnotationValueInfo> values = new ArrayList<>();
1644 boolean any = false;
1645 switch (val.element().name()) {
1646 case "value":
1647 values.add(val);
1648 break;
1649 case "allOf":
1650 values = (ArrayList<AnnotationValueInfo>) val.value();
1651 break;
1652 case "anyOf":
1653 any = true;
1654 values = (ArrayList<AnnotationValueInfo>) val.value();
1655 break;
1656 }
1657 if (values.isEmpty()) continue;
1658
1659 ArrayList<String> system = new ArrayList<>();
1660 ArrayList<String> nonSystem = new ArrayList<>();
1661 for (AnnotationValueInfo value : values) {
1662 final String perm = String.valueOf(value.value());
1663 final String level = Doclava.manifestPermissions.getOrDefault(perm, null);
1664 if (level == null) {
1665 Errors.error(Errors.REMOVED_FIELD, mi.position(),
1666 "Permission '" + perm + "' is not defined by AndroidManifest.xml.");
1667 continue;
1668 }
1669 if (level.contains("normal") || level.contains("dangerous")
1670 || level.contains("ephemeral")) {
1671 nonSystem.add(perm);
1672 } else {
1673 system.add(perm);
1674 }
1675 }
1676
1677 if (system.isEmpty() && nonSystem.isEmpty()) {
1678 hasAnnotation = false;
1679 } else if ((any && !nonSystem.isEmpty()) || (!any && system.isEmpty())) {
1680 Errors.error(Errors.REQUIRES_PERMISSION, mi, "Method '" + mi.name()
1681 + "' must be protected with a system permission; it currently"
1682 + " allows non-system callers holding " + nonSystem.toString());
1683 }
1684 }
1685 }
1686 }
1687 if (!hasAnnotation) {
1688 Errors.error(Errors.REQUIRES_PERMISSION, mi, "Method '" + mi.name()
1689 + "' must be protected with a system permission.");
1690 }
1691 }
1692
1693 private static void checkHiddenTypes(MethodInfo method, Predicate<MemberInfo> filterReference) {
1694 checkHiddenTypes(method.returnType(), method, filterReference);
1695 List<ParameterInfo> params = method.parameters();
1696 if (params != null) {
1697 for (ParameterInfo param : params) {
1698 checkHiddenTypes(param.type(), method, filterReference);
1699 }
1700 }
1701 }
1702
1703 private static void checkHiddenTypes(FieldInfo field, Predicate<MemberInfo> filterReference) {
1704 checkHiddenTypes(field.type(), field, filterReference);
1705 }
1706
1707 private static void checkHiddenTypes(TypeInfo type, MemberInfo member,
1708 Predicate<MemberInfo> filterReference) {
1709 if (type == null || type.isPrimitive()) {
1710 return;
1711 }
1712
1713 ClassInfo clazz = type.asClassInfo();
1714 if (clazz == null || !filterReference.test(clazz.asMemberInfo())) {
1715 Errors.error(Errors.HIDDEN_TYPE_PARAMETER, member.position(),
1716 "Member " + member + " references hidden type " + type.qualifiedTypeName() + ".");
1717 }
1718
1719 List<TypeInfo> args = type.typeArguments();
1720 if (args != null) {
1721 for (TypeInfo arg : args) {
1722 checkHiddenTypes(arg, member, filterReference);
1723 }
1724 }
1725 }
1726
1727 static void writeConstructorApi(PrintStream apiWriter, MethodInfo mi) {
1728 apiWriter.print(" ctor ");
1729 apiWriter.print(mi.scope());
1730 if (mi.isDeprecated()) {
1731 apiWriter.print(" deprecated");
1732 }
1733 apiWriter.print(" ");
1734 apiWriter.print(mi.name());
1735
1736 writeParametersApi(apiWriter, mi, mi.parameters());
1737 writeThrowsApi(apiWriter, mi.thrownExceptions());
1738 apiWriter.print(";\n");
1739 }
1740
1741 static String writeMethodApiWithoutDefault(MethodInfo mi) {
1742 final ByteArrayOutputStream out = new ByteArrayOutputStream();
1743 writeMethodApi(new PrintStream(out), mi, false);
1744 return out.toString();
1745 }
1746
1747 static void writeMethodApi(PrintStream apiWriter, MethodInfo mi) {
1748 writeMethodApi(apiWriter, mi, true);
1749 }
1750
1751 static void writeMethodApi(PrintStream apiWriter, MethodInfo mi, boolean withDefault) {
1752 apiWriter.print(" method ");
1753 apiWriter.print(mi.scope());
1754 if (mi.isDefault() && withDefault) {
1755 apiWriter.print(" default");
1756 }
1757 if (mi.isStatic()) {
1758 apiWriter.print(" static");
1759 }
1760 if (mi.isFinal()) {
1761 apiWriter.print(" final");
1762 }
1763 if (mi.isAbstract()) {
1764 apiWriter.print(" abstract");
1765 }
1766 if (mi.isDeprecated()) {
1767 apiWriter.print(" deprecated");
1768 }
1769 if (mi.isSynchronized()) {
1770 apiWriter.print(" synchronized");
1771 }
1772 if (mi.hasTypeParameters()) {
1773 apiWriter.print(" " + mi.typeArgumentsName(new HashSet<String>()));
1774 }
1775 apiWriter.print(" ");
1776 if (mi.returnType() == null) {
1777 apiWriter.print("void");
1778 } else {
1779 apiWriter.print(fullParameterTypeName(mi, mi.returnType(), false));
1780 }
1781 apiWriter.print(" ");
1782 apiWriter.print(mi.name());
1783
1784 writeParametersApi(apiWriter, mi, mi.parameters());
1785 writeThrowsApi(apiWriter, mi.thrownExceptions());
1786
1787 apiWriter.print(";\n");
1788 }
1789
1790 static void writeMethodDexApi(PrintStream apiWriter, ClassInfo cl, MethodInfo mi) {
1791 apiWriter.print(toSlashFormat(cl.qualifiedName()));
1792 apiWriter.print("->");
1793 if (mi.returnType() == null) {
1794 apiWriter.print("<init>");
1795 } else {
1796 apiWriter.print(mi.name());
1797 }
1798 writeParametersDexApi(apiWriter, mi, mi.parameters());
1799 if (mi.returnType() == null) { // constructor
1800 apiWriter.print("V");
1801 } else {
1802 apiWriter.print(toSlashFormat(mi.returnType().dexName()));
1803 }
1804 apiWriter.print("\n");
1805 }
1806
1807 static void writeParametersApi(PrintStream apiWriter, MethodInfo method,
1808 ArrayList<ParameterInfo> params) {
1809 apiWriter.print("(");
1810
1811 for (ParameterInfo pi : params) {
1812 if (pi != params.get(0)) {
1813 apiWriter.print(", ");
1814 }
1815 apiWriter.print(fullParameterTypeName(method, pi.type(), pi == params.get(params.size()-1)));
1816 // turn on to write the names too
1817 if (false) {
1818 apiWriter.print(" ");
1819 apiWriter.print(pi.name());
1820 }
1821 }
1822
1823 apiWriter.print(")");
1824 }
1825
1826 static void writeParametersDexApi(PrintStream apiWriter, MethodInfo method,
1827 ArrayList<ParameterInfo> params) {
1828 apiWriter.print("(");
1829 for (ParameterInfo pi : params) {
1830 String typeName = pi.type().dexName();
1831 if (method.isVarArgs() && pi == params.get(params.size() - 1)) {
1832 typeName += "[]";
1833 }
1834 apiWriter.print(toSlashFormat(typeName));
1835 }
1836 apiWriter.print(")");
1837 }
1838
1839 static void writeThrowsApi(PrintStream apiWriter, ArrayList<ClassInfo> exceptions) {
1840 // write in a canonical order
1841 exceptions = (ArrayList<ClassInfo>) exceptions.clone();
1842 Collections.sort(exceptions, ClassInfo.comparator);
1843 //final int N = exceptions.length;
1844 boolean first = true;
1845 for (ClassInfo ex : exceptions) {
1846 // Turn this off, b/c we need to regenrate the old xml files.
1847 if (true || !"java.lang.RuntimeException".equals(ex.qualifiedName())
1848 && !ex.isDerivedFrom("java.lang.RuntimeException")) {
1849 if (first) {
1850 apiWriter.print(" throws ");
1851 first = false;
1852 } else {
1853 apiWriter.print(", ");
1854 }
1855 apiWriter.print(ex.qualifiedName());
1856 }
1857 }
1858 }
1859
1860 static void writeFieldApi(PrintStream apiWriter, FieldInfo fi, String label) {
1861 apiWriter.print(" ");
1862 apiWriter.print(label);
1863 apiWriter.print(" ");
1864 apiWriter.print(fi.scope());
1865 if (fi.isStatic()) {
1866 apiWriter.print(" static");
1867 }
1868 if (fi.isFinal()) {
1869 apiWriter.print(" final");
1870 }
1871 if (fi.isDeprecated()) {
1872 apiWriter.print(" deprecated");
1873 }
1874 if (fi.isTransient()) {
1875 apiWriter.print(" transient");
1876 }
1877 if (fi.isVolatile()) {
1878 apiWriter.print(" volatile");
1879 }
1880
1881 apiWriter.print(" ");
1882 apiWriter.print(fi.type().fullName(fi.typeVariables()));
1883
1884 apiWriter.print(" ");
1885 apiWriter.print(fi.name());
1886
1887 Object val = null;
1888 if (fi.isConstant() && fieldIsInitialized(fi)) {
1889 apiWriter.print(" = ");
1890 apiWriter.print(fi.constantLiteralValue());
1891 val = fi.constantValue();
1892 }
1893
1894 apiWriter.print(";");
1895
1896 if (val != null) {
1897 if (val instanceof Integer && "char".equals(fi.type().qualifiedTypeName())) {
1898 apiWriter.format(" // 0x%04x '%s'", val,
1899 FieldInfo.javaEscapeString("" + ((char)((Integer)val).intValue())));
1900 } else if (val instanceof Byte || val instanceof Short || val instanceof Integer) {
1901 apiWriter.format(" // 0x%x", val);
1902 } else if (val instanceof Long) {
1903 apiWriter.format(" // 0x%xL", val);
1904 }
1905 }
1906
1907 apiWriter.print("\n");
1908 }
1909
1910 static void writeFieldDexApi(PrintStream apiWriter, ClassInfo cl, FieldInfo fi) {
1911 apiWriter.print(toSlashFormat(cl.qualifiedName()));
1912 apiWriter.print("->");
1913 apiWriter.print(fi.name());
1914 apiWriter.print(":");
1915 apiWriter.print(toSlashFormat(fi.type().dexName()));
1916 apiWriter.print("\n");
1917 }
1918
1919 static void writeKeepList(PrintStream keepListWriter,
1920 HashMap<PackageInfo, List<ClassInfo>> allClasses, HashSet<ClassInfo> notStrippable) {
1921 // extract the set of packages, sort them by name, and write them out in that order
1922 Set<PackageInfo> allClassKeys = allClasses.keySet();
1923 PackageInfo[] allPackages = allClassKeys.toArray(new PackageInfo[allClassKeys.size()]);
1924 Arrays.sort(allPackages, PackageInfo.comparator);
1925
1926 for (PackageInfo pack : allPackages) {
1927 writePackageKeepList(keepListWriter, pack, allClasses.get(pack), notStrippable);
1928 }
1929 }
1930
1931 static void writePackageKeepList(PrintStream keepListWriter, PackageInfo pack,
1932 Collection<ClassInfo> classList, HashSet<ClassInfo> notStrippable) {
1933 // Work around the bogus "Array" class we invent for
1934 // Arrays.copyOf's Class<? extends T[]> newType parameter. (http://b/2715505)
1935 if (pack.name().equals(PackageInfo.DEFAULT_PACKAGE)) {
1936 return;
1937 }
1938
1939 ClassInfo[] classes = classList.toArray(new ClassInfo[classList.size()]);
1940 Arrays.sort(classes, ClassInfo.comparator);
1941 for (ClassInfo cl : classes) {
1942 writeClassKeepList(keepListWriter, cl, notStrippable);
1943 }
1944 }
1945
1946 static void writeClassKeepList(PrintStream keepListWriter, ClassInfo cl,
1947 HashSet<ClassInfo> notStrippable) {
1948 keepListWriter.print("-keep class ");
1949 keepListWriter.print(to$Class(cl.qualifiedName()));
1950
1951 keepListWriter.print(" {\n");
1952
1953 ArrayList<MethodInfo> constructors = cl.constructors();
1954 Collections.sort(constructors, MethodInfo.comparator);
1955 for (MethodInfo mi : constructors) {
1956 writeConstructorKeepList(keepListWriter, mi);
1957 }
1958
1959 keepListWriter.print("\n");
1960
1961 ArrayList<MethodInfo> methods = cl.allSelfMethods();
1962 Collections.sort(methods, MethodInfo.comparator);
1963 for (MethodInfo mi : methods) {
1964 // allSelfMethods is the non-hidden and visible methods. See Doclava.checkLevel.
1965 writeMethodKeepList(keepListWriter, mi);
1966 }
1967
1968 keepListWriter.print("\n");
1969
1970 ArrayList<FieldInfo> enums = cl.enumConstants();
1971 Collections.sort(enums, FieldInfo.comparator);
1972 for (FieldInfo fi : enums) {
1973 writeFieldKeepList(keepListWriter, fi);
1974 }
1975
1976 keepListWriter.print("\n");
1977
1978 ArrayList<FieldInfo> fields = cl.selfFields();
1979 Collections.sort(fields, FieldInfo.comparator);
1980 for (FieldInfo fi : fields) {
1981 writeFieldKeepList(keepListWriter, fi);
1982 }
1983
1984 keepListWriter.print("}\n\n");
1985 }
1986
1987 static void writeConstructorKeepList(PrintStream keepListWriter, MethodInfo mi) {
1988 keepListWriter.print(" ");
1989 keepListWriter.print("<init>");
1990
1991 writeParametersKeepList(keepListWriter, mi, mi.parameters());
1992 keepListWriter.print(";\n");
1993 }
1994
1995 static void writeMethodKeepList(PrintStream keepListWriter, MethodInfo mi) {
1996 keepListWriter.print(" ");
1997 keepListWriter.print(mi.scope());
1998 if (mi.isStatic()) {
1999 keepListWriter.print(" static");
2000 }
2001 if (mi.isAbstract()) {
2002 keepListWriter.print(" abstract");
2003 }
2004 if (mi.isSynchronized()) {
2005 keepListWriter.print(" synchronized");
2006 }
2007 keepListWriter.print(" ");
2008 if (mi.returnType() == null) {
2009 keepListWriter.print("void");
2010 } else {
2011 keepListWriter.print(getCleanTypeName(mi.returnType()));
2012 }
2013 keepListWriter.print(" ");
2014 keepListWriter.print(mi.name());
2015
2016 writeParametersKeepList(keepListWriter, mi, mi.parameters());
2017
2018 keepListWriter.print(";\n");
2019 }
2020
2021 static void writeParametersKeepList(PrintStream keepListWriter, MethodInfo method,
2022 ArrayList<ParameterInfo> params) {
2023 keepListWriter.print("(");
2024
2025 for (ParameterInfo pi : params) {
2026 if (pi != params.get(0)) {
2027 keepListWriter.print(", ");
2028 }
2029 keepListWriter.print(getCleanTypeName(pi.type()));
2030 }
2031
2032 keepListWriter.print(")");
2033 }
2034
2035 static void writeFieldKeepList(PrintStream keepListWriter, FieldInfo fi) {
2036 keepListWriter.print(" ");
2037 keepListWriter.print(fi.scope());
2038 if (fi.isStatic()) {
2039 keepListWriter.print(" static");
2040 }
2041 if (fi.isTransient()) {
2042 keepListWriter.print(" transient");
2043 }
2044 if (fi.isVolatile()) {
2045 keepListWriter.print(" volatile");
2046 }
2047
2048 keepListWriter.print(" ");
2049 keepListWriter.print(getCleanTypeName(fi.type()));
2050
2051 keepListWriter.print(" ");
2052 keepListWriter.print(fi.name());
2053
2054 keepListWriter.print(";\n");
2055 }
2056
2057 static String fullParameterTypeName(MethodInfo method, TypeInfo type, boolean isLast) {
2058 String fullTypeName = type.fullName(method.typeVariables());
2059 if (isLast && method.isVarArgs()) {
2060 // TODO: note that this does not attempt to handle hypothetical
2061 // vararg methods whose last parameter is a list of arrays, e.g.
2062 // "Object[]...".
2063 fullTypeName = type.fullNameNoDimension(method.typeVariables()) + "...";
2064 }
2065 return fullTypeName;
2066 }
2067
2068 static String to$Class(String name) {
2069 int pos = 0;
2070 while ((pos = name.indexOf('.', pos)) > 0) {
2071 String n = name.substring(0, pos);
2072 if (Converter.obtainClass(n) != null) {
2073 return n + (name.substring(pos).replace('.', '$'));
2074 }
2075 pos = pos + 1;
2076 }
2077 return name;
2078 }
2079
2080 static String toSlashFormat(String name) {
2081 String dimension = "";
2082 while (name.endsWith("[]")) {
2083 dimension += "[";
2084 name = name.substring(0, name.length() - 2);
2085 }
2086
2087 final String base;
2088 if (name.equals("void")) {
2089 base = "V";
2090 } else if (name.equals("byte")) {
2091 base = "B";
2092 } else if (name.equals("boolean")) {
2093 base = "Z";
2094 } else if (name.equals("char")) {
2095 base = "C";
2096 } else if (name.equals("short")) {
2097 base = "S";
2098 } else if (name.equals("int")) {
2099 base = "I";
2100 } else if (name.equals("long")) {
2101 base = "J";
2102 } else if (name.equals("float")) {
2103 base = "F";
2104 } else if (name.equals("double")) {
2105 base = "D";
2106 } else {
2107 base = "L" + to$Class(name).replace(".", "/") + ";";
2108 }
2109
2110 return dimension + base;
2111 }
2112
2113 static String getCleanTypeName(TypeInfo t) {
2114 return t.isPrimitive() ? t.simpleTypeName() + t.dimension() :
2115 to$Class(t.asClassInfo().qualifiedName() + t.dimension());
2116 }
2117 }
android系统源码编译报错问题分析处理--持续更新的更多相关文章
- [odroid-pc] ubuntu12.04 64bit Android4.0.3 源码编译报错及解决的方法
第一个错误: host Executable: cmu2nuance (out/host/linux-x86/obj/EXECUTABLES/cmu2nuance_intermedia ...
- 【转】编译Android系统源码和内核源码
原文网址:http://blog.csdn.net/jiangwei0910410003/article/details/37988637 好长时间没有写blog了,之所以没有写,主要还是工作上的事, ...
- FW 编译Android系统源码和内核源码
编译Android系统源码和内核源码 分类: Android2014-07-21 20:58 7287人阅读 评论(28) 收藏 举报 好长时间没有写blog了,之所以没有写,主要还是工作上的事,发现 ...
- 编译Android系统源码和内核源码
[日期:2016-01-11] 来源:Linux社区 作者:jiangwei [字体:大 中 小] 把我之前编译Android系统源码和内核源码的过程记录一下,因为这个过程真的是受益匪浅,看 ...
- 【流媒体开发】VLC Media Player - Android 平台源码编译 与 二次开发详解 (提供详细800M下载好的编译源码及eclipse可调试播放器源码下载)
作者 : 韩曙亮 博客地址 : http://blog.csdn.net/shulianghan/article/details/42707293 转载请注明出处 : http://blog.csd ...
- Android FrameWork 学习之Android 系统源码调试
这是很久以前访问掘金的时候 无意间看到的一个关于Android的文章,作者更细心,分阶段的将学习步骤记录在自己博客中,我觉得很有用,想作为分享同时也是留下自己知识的一些欠缺收藏起来,今后做项目的时候会 ...
- 【安卓本卓】Android系统源码篇之(一)源码获取、源码目录结构及源码阅读工具简介
前言 古人常说,“熟读唐诗三百首,不会作诗也会吟”,说明了大量阅读诗歌名篇对学习作诗有非常大的帮助.做开发也一样,Android源码是全世界最优秀的Android工程师编写的代码,也是A ...
- 如何阅读Android系统源码-收藏必备
对于任何一个对Android开发感兴趣的人而言,对于android系统的学习必不可少.而学习系统最佳的方法就如linus所言:"RTFSC"(Read The Fucking So ...
- 将Android系统源码导入Android studio的方法
Android源码目录结构如下: |-- Makefile|-- abi (applicationbinary interface,应用程序二进制接口,生成libgabi++.so相关库文件)|-- ...
- Android系统源码目录
Android系统源码目录 我们要先了解Android系统源码目录,为后期源码学习打下基础.关于源码的阅读,你可以访问http://androidxref.com/来阅读系统源码.当然,最好是将源码下 ...
随机推荐
- 安卓逆向 ARM基础篇
1.ARM 与 Andorid 的关系 android 的操作系统是 LINUX 内核 LINux又是ARM 2.ARM汇编规范 3.ARM指令格式 ARM常用指令开始 1.ARM 的跳转指令 PC ...
- Cesium计算三角形面积(十)
function triangleArea(p0, p1, p2) { //利用subtract计算出两个向量 let v0=Cesium.Cartesian3.subtract(p0,p1,newC ...
- JZOJ 3571. 【GDKOI2014】内存分配
解析 也就是说建一棵权值线段树维护这些信息.要注意的是每次的最优解必然是 \(b\) 小的先做,故离线排序确定离散后的下标再依次求解 \(Code\) #include<cstdio> # ...
- Oracle 备份与恢复 (Docker部署版)
Oracle 备份与恢复 (Docker部署版) 一,宿主机设置定时备份脚本 1.检查Oracle容器是否正常运行 docker ps 2.进入容器,创建shell脚本 #oracle11g 是容器名 ...
- .NET周报 【2月第4期 2023-02-25】
国内文章 .NET微服务系统迁移至.NET6.0的故事 https://www.cnblogs.com/InCerry/p/microservice-migration-net-6.html 本次迁移 ...
- string str = string.Empty也会出错?
如题 为什么会出现这种情况?大佬解释一下.
- C# WCF实现聊天室功能
1.WCF是什么 Windows Communication Foundation(WCF)是由微软开发的一系列支持数据通信的应用程序框架 看这篇文章之前,可以先看我的另一篇文章,初步了解一下WCF: ...
- fabric学习笔记5
fabric学习笔记5 20201303张奕博 2023.1.15 fabric中的docker命令 1.查看本机的镜像列表 docker images 2.拉取镜像 docker pull hype ...
- 关于MFC程序关闭之后仍有线程存留
最近弄了一个项目,关闭之后在任务管理器中依然存留,刚开始以为是因为子线程没能退出,就用ExitThread来终止,终止之后发现好像并不是子线程的原因 查了好久没能找到原因 最后只能通杀 HANDLE ...
- SVN的安装和使用手册2
转载:http://www.cnblogs.com/armyfai/p/3985660.html SVN简介: 为什么要使用SVN? 程序员在编写程序的过程中,每个程序员都会生成很多不同的版本,这就需 ...