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

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

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

Powered by Google App Engine
This is Rietveld 408576698