• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 package libcore;
18 
19 import java.io.File;
20 import java.io.IOException;
21 import java.nio.file.Path;
22 import java.nio.file.Paths;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Objects;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
32 
33 /**
34  * A set of .java files (either from ojluni or from an upstream).
35  */
36 abstract class Repository {
37 
38     /**
39      * Maps from a file's (current) relPath to the corresponding OpenJDK relPath from
40      * which it has been, and still remains, renamed.
41      */
42     static final Map<Path, Path> OPENJDK_REL_PATH = historicRenames();
43 
historicRenames()44     static Map<Path, Path> historicRenames() {
45         Map<Path, Path> result = new HashMap<>();
46         // renamed in libcore commit 583eb0e4738456f0547014a4857a14456be267ee
47         result.put(Paths.get("native/linux_close.cpp"), Paths.get("native/linux_close.c"));
48         // Map ByteBufferAs*Buffer.java to an upstream file, even though there is
49         // not a 1:1 correspondence. This isn't perfect, but allows some rough
50         // comparison. See http://b/111583940
51         //
52         // More detail:
53         // The RI has four different generated files ...Buffer{B,L,RB,RL}.java
54         // for each of these six files specializing on big endian, little endian,
55         // read-only big endian, and read-only little endian, respectively. Those
56         // 6 x 4 files are generated from a single template:
57         //     java/nio/ByteBufferAs-X-Buffer.java.template
58         //
59         // On Android, the four variants {B,L,RB,RL} for each of the six types
60         // are folded into a single class with behavior configured via additional
61         // constructor arguments.
62         //
63         // For now, we map to upstream's "B" variant; "B" is more similar to
64         // Android's files than "RB" or "RL"; the choice of "B" vs. "L" is arbitrary.
65         for (String s : Arrays.asList("Char", "Double", "Float", "Int", "Long", "Short")) {
66             Path ojluniPath = Paths.get("java/nio/ByteBufferAs" + s + "Buffer.java");
67             Path upstreamPath =
68                     Paths.get("java/nio/ByteBufferAs" + s + "BufferB.java");
69             result.put(ojluniPath, upstreamPath);
70         }
71         return Collections.unmodifiableMap(result);
72     }
73 
74     protected final Path rootPath;
75     protected final String name;
76     protected final List<String> sourceDirs;
77 
Repository(Path rootPath, String name, List<String> sourceDirs)78     protected Repository(Path rootPath, String name, List<String> sourceDirs) {
79         this.rootPath = Objects.requireNonNull(rootPath);
80         this.name = Objects.requireNonNull(name);
81         this.sourceDirs = Objects.requireNonNull(sourceDirs);
82         if (!rootPath.toFile().isDirectory()) {
83             throw new IllegalArgumentException("Missing or not a directory: " + rootPath);
84         }
85     }
86 
87     /**
88      * @param relPath a relative path of a .java file in the repository, e.g.
89      *        "java/util/ArrayList.java".
90      * @return the path of the indicated file (either absolute, or relative to the current
91      *         working directory), or null if the file does not exist in this Repository.
92      */
absolutePath(Path relPath)93     public final Path absolutePath(Path relPath) {
94         Path p = pathFromRepository(relPath);
95         return p == null ? null : rootPath.resolve(p).toAbsolutePath();
96     }
97 
pathFromRepository(Path relPath)98     public Path pathFromRepository(Path relPath) {
99         // Search across all sourceDirs for the indicated file.
100         for (String sourceDir : sourceDirs) {
101             Path repositoryRelativePath = Paths.get(sourceDir).resolve(relPath);
102             File file = rootPath.resolve(repositoryRelativePath).toFile();
103             if (file.exists()) {
104                 return repositoryRelativePath;
105             }
106         }
107         return null;
108     }
109 
rootPath()110     public final Path rootPath() {
111         return rootPath;
112     }
113 
114     @Override
hashCode()115     public int hashCode() {
116       return rootPath.hashCode();
117     }
118 
119     @Override
equals(Object obj)120     public boolean equals(Object obj) {
121       return (obj instanceof Repository) && rootPath.equals(((Repository) obj).rootPath);
122     }
123 
124     /**
125      * @return A human readable name to identify this repository, suitable for use as a
126      *         directory name.
127      */
name()128     public final String name() {
129         return name;
130     }
131 
132     @Override
toString()133     public String toString() {
134         return name() + " repository";
135     }
136 
137     /**
138      * A checkout of the hg repository of OpenJDK 9 or higher, located in the
139      * subdirectory {@code upstreamName} under the directory {@code upstreamRoot}.
140      */
openJdk9(Path upstreamRoot, String upstreamName)141     public static Repository openJdk9(Path upstreamRoot, String upstreamName) {
142         List<String> sourceDirs = Arrays.asList(
143             "jdk/src/java.base/share/classes",
144             "jdk/src/java.logging/share/classes",
145             "jdk/src/java.prefs/share/classes",
146             "jdk/src/java.sql/share/classes",
147             "jdk/src/java.desktop/share/classes",
148             "jdk/src/java.base/solaris/classes",
149             "jdk/src/java.base/unix/classes",
150             "jdk/src/java.prefs/unix/classes",
151             "jdk/src/jdk.unsupported/share/classes",
152             "jdk/src/jdk.net/share/classes",
153             "jdk/src/java.base/linux/classes",
154             "build/linux-x86_64-normal-server-release/support/gensrc/java.base",
155 
156             // Native (.c) files
157             "jdk/src/java.base/unix/native/libjava",
158             "jdk/src/java.base/share/native/libjava",
159             "jdk/src/java.base/unix/native/libnio",
160             "jdk/src/java.base/unix/native/libnio/ch",
161             "jdk/src/java.base/unix/native/libnio/fs",
162             "jdk/src/java.base/unix/native/libnet"
163         );
164         return new OpenJdkRepository(upstreamRoot, upstreamName, sourceDirs);
165     }
166 
167     /**
168      * A checkout of the hg repository of OpenJDK 8 or earlier, located in the
169      * subdirectory {@code upstreamName} under the directory {@code upstreamRoot}.
170      */
openJdkLegacy(Path upstreamRoot, String upstreamName)171     public static Repository openJdkLegacy(Path upstreamRoot, String upstreamName) {
172         List<String> sourceDirs = new ArrayList<>();
173         sourceDirs.addAll(Arrays.asList(
174             "jdk/src/share/classes",
175             "jdk/src/solaris/classes",
176             "build/linux-x86_64-normal-server-release/jdk/gensrc"
177         ));
178 
179         // In legacy OpenJDK versions, the source files are organized into a subfolder
180         // hierarchy based on package name, whereas in Android and OpenJDK 9+ they're in
181         // a flat folder. We work around this by just searching through all of the
182         // applicable folders (from which we have sources) in legacy OpenJDK versions.
183         List<String> nativeSourceDirs = new ArrayList<>();
184         List<String> pkgPaths = Arrays.asList("", "java/io", "java/lang", "java/net", "java/nio",
185             "java/util", "java/util/zip", "sun/nio/ch", "sun/nio/fs");
186         for (String pkgPath : pkgPaths) {
187             nativeSourceDirs.add("jdk/src/solaris/native/" + pkgPath);
188             nativeSourceDirs.add("jdk/src/share/native/" + pkgPath);
189             nativeSourceDirs.add("jdk/src/solaris/native/common/" + pkgPath);
190             nativeSourceDirs.add("jdk/src/share/native/common/" + pkgPath);
191         }
192         sourceDirs.addAll(nativeSourceDirs);
193 
194         return new OpenJdkRepository(upstreamRoot, upstreamName, sourceDirs);
195     }
196 
197     /**
198      * Checkouts of hg repositories of OpenJDK 8 or earlier, located in the
199      * respective {@code upstreamNames} subdirectories under the join parent
200      * directory {@code upstreamRoot}.
201      */
openJdkLegacy(Path upstreamRoot, List<String> upstreamNames)202     public static List<Repository> openJdkLegacy(Path upstreamRoot, List<String> upstreamNames) {
203         List<Repository> result = new ArrayList<>();
204         for (String upstreamName : upstreamNames) {
205             result.add(openJdkLegacy(upstreamRoot, upstreamName));
206         }
207         return Collections.unmodifiableList(result);
208     }
209 
210     static class OjluniRepository extends Repository {
211         /**
212          * The repository of ojluni java files belonging to the Android sources under
213          * {@code buildTop}.
214          *
215          * @param buildTop The root path of an Android checkout, as identified by the
216          *        {@quote ANDROID_BUILD_TOP} environment variable.
217          */
OjluniRepository(Path buildTop)218         public OjluniRepository(Path buildTop) {
219             super(buildTop.resolve("libcore"), "ojluni",
220                 /* sourceDirs */ Arrays.asList("ojluni/src/main/java", "ojluni/src/main/native"));
221         }
222 
223 
224         @Override
pathFromRepository(Path relPath)225         public Path pathFromRepository(Path relPath) {
226             // Enforce that the file exists in ojluni
227             return Objects.requireNonNull(super.pathFromRepository(relPath));
228         }
229 
230         /**
231          * Returns the list of relative paths to files parsed from blueprint files.
232          */
loadRelPathsFromBlueprint()233         public List<Path> loadRelPathsFromBlueprint() throws IOException {
234             List<Path> result = new ArrayList<>();
235             result.addAll(loadRelPathsFromBlueprint(
236                 "openjdk_java_files.bp", "\"ojluni/src/main/java/(.+\\.java)\""));
237             result.addAll(loadRelPathsFromBlueprint(
238                 "ojluni/src/main/native/Android.bp", "\\s+\"(.+\\.(?:c|cpp))\","));
239             return result;
240         }
241 
loadRelPathsFromBlueprint( String blueprintPathString, String patternString)242         private List<Path> loadRelPathsFromBlueprint(
243             String blueprintPathString, String patternString) throws IOException {
244             Path blueprintPath = rootPath.resolve(blueprintPathString);
245             Pattern pattern = Pattern.compile(patternString);
246             List<Path> result = new ArrayList<>();
247             for (String line : Util.readLines(blueprintPath)) {
248                 Matcher matcher = pattern.matcher(line);
249                 while (matcher.find()) {
250                     Path relPath = Paths.get(matcher.group(1));
251                     result.add(relPath);
252                 }
253             }
254             Collections.sort(result);
255             return result;
256         }
257 
258         @Override
toString()259         public String toString() {
260             return "libcore ojluni";
261         }
262     }
263 
264     static class OpenJdkRepository extends Repository {
265 
OpenJdkRepository(Path upstreamRoot, String name, List<String> sourceDirs)266         public OpenJdkRepository(Path upstreamRoot, String name, List<String> sourceDirs) {
267             super(upstreamRoot.resolve(name), name, sourceDirs);
268         }
269 
270         @Override
pathFromRepository(Path relPath)271         public Path pathFromRepository(Path relPath) {
272             if (OPENJDK_REL_PATH.containsKey(relPath)) {
273                 relPath = OPENJDK_REL_PATH.get(relPath);
274             }
275             return super.pathFromRepository(relPath);
276         }
277 
278         @Override
toString()279         public String toString() {
280             return "OpenJDK " + name;
281         }
282     }
283 
284 }
285