Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Side by Side Diff: chrome/android/webapk/libs/client/src/org/chromium/webapk/lib/client/DexOptimizer.java

Issue 1981473002: Upstream: DexOptimizer and DexLoader classes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/android/webapk/libs/client/DEPS ('k') | chrome/android/webapk/shell_apk/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.webapk.lib.client;
6
7 import android.os.Build;
8 import android.util.Log;
9
10 import dalvik.system.DexClassLoader;
11 import dalvik.system.DexFile;
12
13 import org.chromium.base.annotations.SuppressFBWarnings;
14
15 import java.io.File;
16 import java.io.IOException;
17 import java.lang.reflect.InvocationTargetException;
18 import java.lang.reflect.Method;
19
20 /**
21 * This class provides a method to optimize .dex files.
22 * Note: This class is copied (mostly) verbatim from DexOptUtils in GMSCore.
23 */
24 public class DexOptimizer {
25 private static final String TAG = "cr_DexOptimzer";
26
27 private static final String DEX_SUFFIX = ".dex";
28 private static final String ODEX_SUFFIX = ".odex";
29
30 /**
31 * Creates optimized odex file for the specified dex file.
32 * @param dexFile Path to a dex file.
33 * @return True if the dex file was successfully optimized.
34 */
35 @SuppressFBWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED")
36 public static boolean optimize(File dexFile) {
37 if (!dexFile.exists()) {
38 Log.e(TAG, "Dex file does not exist! " + dexFile.getAbsolutePath());
39 return false;
40 }
41
42 try {
43 if (!DexFile.isDexOptNeeded(dexFile.getAbsolutePath())) {
44 return true;
45 }
46 } catch (Exception e) {
47 Log.e(TAG, "Failed to check optimization status: " + e.toString() + " : "
48 + e.getMessage());
49 }
50
51 File odexDir = null;
52 try {
53 odexDir = ensureOdexDirectory(dexFile);
54 } catch (IOException e) {
55 Log.e(TAG, "Failed to create odex directory! " + e.getMessage());
56 return false;
57 }
58
59 File generatedDexDir = odexDir;
60 if (generatedDexDir.equals(dexFile.getParentFile())) {
61 generatedDexDir = new File(odexDir, "optimized");
62 if (!generatedDexDir.exists() && !generatedDexDir.mkdirs()) {
63 return false;
64 }
65 }
66
67 new DexClassLoader(
68 dexFile.getAbsolutePath(),
69 generatedDexDir.getAbsolutePath(),
70 null,
71 ClassLoader.getSystemClassLoader());
72 File optimizedFile = new File(generatedDexDir, dexFile.getName());
73 if (!optimizedFile.exists()) {
74 Log.e(TAG, "Failed to create dex.");
75 return false;
76 }
77
78 File destOdexFile = new File(odexDir, replaceExtension(optimizedFile.get Name(), "odex"));
79 if (!optimizedFile.renameTo(destOdexFile)) {
80 Log.e(TAG, "Failed to rename optimized file.");
81 return false;
82 }
83
84 if (!destOdexFile.setReadable(true, false)) {
85 Log.e(TAG, "Failed to make odex world readable.");
86 return false;
87 }
88
89 return true;
90 }
91
92 /**
93 * Guesses the directory that DexClassLoader looks in for the odex file base d on the
94 * Android OS version and the dex path.
95 * @param dexPath
96 * @return Guess for the default odex directory.
97 */
98 private static File odexDirectory(File dexPath) {
99 int currentApiVersion = Build.VERSION.SDK_INT;
100 try {
101 if (currentApiVersion >= Build.VERSION_CODES.M) {
102 return new File(
103 dexPath.getParentFile(), "oat/" + VMRuntime.getCurrentIn structionSet());
104 } else if (currentApiVersion >= Build.VERSION_CODES.LOLLIPOP) {
105 return new File(dexPath.getParentFile(), VMRuntime.getCurrentIns tructionSet());
106 } else {
107 return dexPath.getParentFile();
108 }
109 } catch (NoSuchMethodException e) {
110 return null;
111 }
112 }
113
114 /**
115 * Guesses the directory that DexClassLoader looks in for the odex file base d on the
116 * Android OS version and the dex path. Creates the directory if it does not exist.
117 * @param dexPath
118 * @return Guess for the default odex directory.
119 */
120 private static File ensureOdexDirectory(File dexPath) throws IOException {
121 File odexDir = odexDirectory(dexPath);
122 if (odexDir == null) {
123 throw new IOException("Failed to create odex cache directory. "
124 + "Could not determine odex directory.");
125 }
126 if (!odexDir.exists()) {
127 boolean success = odexDir.mkdirs();
128 if (!success) {
129 throw new IOException(
130 "Failed to create odex cache directory in data directory .");
131 }
132 // The full path to the odex must be traversable.
133 File root = dexPath.getParentFile();
134 File dir = odexDir;
135 while (dir != null && !root.equals(dir)) {
136 if (!dir.setExecutable(true, false)) {
137 throw new IOException("Failed to make odex directory world t raversable: "
138 + dir.getAbsolutePath());
139 }
140 dir = dir.getParentFile();
141 }
142 }
143 return odexDir;
144 }
145
146 /**
147 * Replaces a file name's extension.
148 *
149 * @param name File name to modify.
150 * @param extension New extension.
151 * @return File name with new extension.
152 */
153 private static String replaceExtension(String name, String extension) {
154 int lastDot = name.lastIndexOf(".");
155 StringBuilder sb = new StringBuilder(lastDot + extension.length());
156 sb.append(name, 0, lastDot + 1);
157 sb.append(extension);
158 return sb.toString();
159 }
160
161 /**
162 * Makes use of a hidden API to retrieve the instruction set name for the cu rrently
163 * executing process. This string is used to form the directory name for the generated
164 * odex.
165 *
166 * - This API is not available on pre-L devices, but as the pre-L runtime di d not scope odex
167 * files by <isa> on pre-L, this is not a problem.
168 *
169 * - For devices L+, it's still possible for this API to be missing. In that case
170 * we will fallback to A) interpretation, and failing that B) generate an odex in the
171 * client's file space.
172 */
173 private static class VMRuntime {
174 @SuppressWarnings("unchecked")
175 public static String getCurrentInstructionSet() throws NoSuchMethodExcep tion {
176 Method getCurrentInstructionSetMethod;
177 try {
178 Class c = Class.forName("dalvik.system.VMRuntime");
179 getCurrentInstructionSetMethod = c.getDeclaredMethod("getCurrent InstructionSet");
180 } catch (ClassNotFoundException | NoSuchMethodException e) {
181 Log.w(TAG, "dalvik.system.VMRuntime#getCurrentInstructionSet is unsupported.", e);
182 throw new NoSuchMethodException(
183 "dalvik.system.VMRuntime#getCurrentInstructionSet could not be found.");
184 }
185 try {
186 return (String) getCurrentInstructionSetMethod.invoke(null);
187 } catch (IllegalAccessException | InvocationTargetException e) {
188 Log.w(TAG, "Failed to call dalvik.system.VMRuntime#getCurrentIns tructionSet", e);
189 throw new NoSuchMethodException(
190 "dalvik.system.VMRuntime#getCurrentInstructionSet could not be found.");
191 }
192 }
193 }
194 }
OLDNEW
« no previous file with comments | « chrome/android/webapk/libs/client/DEPS ('k') | chrome/android/webapk/shell_apk/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698