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

Side by Side Diff: chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/DexLoader.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/shell_apk/javatests/src/org/chromium/webapk/shell_apk/DexLoaderTest.java ('k') | no next file » | 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.shell_apk;
6
7 import android.content.Context;
8 import android.util.Log;
9
10 import dalvik.system.BaseDexClassLoader;
11
12 import java.io.File;
13 import java.io.FileOutputStream;
14 import java.io.IOException;
15 import java.io.InputStream;
16
17 /**
18 * Creates ClassLoader for .dex file in a remote Context's APK.
19 */
20 public class DexLoader {
21 private static final int BUFFER_SIZE = 16 * 1024;
22 private static final String TAG = "cr.DexLoader";
23
24 /**
25 * Creates ClassLoader for .dex file in {@link remoteContext}'s APK.
26 * @param remoteContext The context with the APK with the .dex file.
27 * @param dexName The name of the .dex file in the APK.
28 * @param canaryClassName Name of class in the .dex file. Used for testing t he ClassLoader
29 * before returning it.
30 * @param remoteDexFile Location of already extracted .dex file from APK.
31 * @param localDexDir Writable directory for caching data to speed up future calls to
32 * {@link #load()}.
33 * @return The ClassLoader. Returns null on an error.
34 */
35 public static ClassLoader load(Context remoteContext, String dexName, String canaryClassName,
36 File remoteDexFile, File localDexDir) {
37 File localDexFile = new File(localDexDir, dexName);
38
39 // If {@link localDexFile} exists, technique #2 was previously used to c reate the
40 // ClassLoader. Skip right to the technique which worked last time.
41 if (remoteDexFile != null && remoteDexFile.exists() && !localDexFile.exi sts()) {
42 // Technique #1: At startup, Chrome code extracts the .dex file from its assets and
43 // guesses where DexClassLoader searches for the odex by default and puts the odex
44 // there. Try using the odex from Chrome's data directory.
45 ClassLoader loader = tryCreatingClassLoader(canaryClassName, remoteD exFile, null);
46 if (loader != null) {
47 return loader;
48 }
49 }
50
51 // Technique #2: Extract the .dex file from the remote context's APK. Cr eate a
52 // ClassLoader from the extracted file.
53 if (!localDexFile.exists() || localDexFile.length() == 0) {
54 if (!localDexDir.exists() && !localDexDir.mkdirs()) {
55 return null;
56 }
57
58 InputStream inputStream;
59 try {
60 inputStream = remoteContext.getAssets().open(dexName);
61 } catch (Exception e) {
62 Log.w(TAG, "Could not extract dex from assets");
63 e.printStackTrace();
64 return null;
65 }
66 copyFromInputStream(inputStream, localDexFile);
67 }
68
69 File localOptimizedDir = new File(localDexDir, "optimized");
70 if (!localOptimizedDir.exists() && !localOptimizedDir.mkdirs()) {
71 return null;
72 }
73
74 return tryCreatingClassLoader(canaryClassName, localDexFile, localOptimi zedDir);
75 }
76
77 /**
78 * Deletes any files cached by {@link #load()}.
79 * @param localDexDir Cache directory passed to {@link #load()}.
80 */
81 public static void deleteCachedDexes(File localDexDir) {
82 deleteChildren(localDexDir);
83 }
84
85 /**
86 * Deletes all of a directory's children including subdirectories.
87 * @param parentDir Directory whose children should be deleted.
88 */
89 private static void deleteChildren(File parentDir) {
90 if (!parentDir.isDirectory()) {
91 return;
92 }
93
94 File[] files = parentDir.listFiles();
95 if (files != null) {
96 for (File file : files) {
97 deleteChildren(file);
98 if (!file.delete()) {
99 Log.e(TAG, "Could not delete " + file.getPath());
100 }
101 }
102 }
103 }
104
105 /**
106 * Copies an InputStream to a file.
107 * @param inputStream
108 * @param outFile The destination file.
109 */
110 private static void copyFromInputStream(InputStream inputStream, File outFil e) {
111 try (FileOutputStream outputStream = new FileOutputStream(outFile)) {
112 byte[] buffer = new byte[BUFFER_SIZE];
113 int count = 0;
114 while ((count = inputStream.read(buffer, 0, BUFFER_SIZE)) != -1) {
115 outputStream.write(buffer, 0, count);
116 }
117 } catch (IOException e) {
118 } finally {
119 try {
120 inputStream.close();
121 } catch (Exception e) {
122 }
123 }
124 }
125
126 /**
127 * Tries to create ClassLoader with the given .dex file and optimized dex di rectory.
128 * @param canaryClassName Name of class in the .dex file. Used for testing t he ClassLoader
129 * before returning it.
130 * @param dexFile .dex file to create ClassLoader for.
131 * @param optimizedDir Directory for storing the optimized dex file. If null , an OS-defined
132 * path based on {@link dexFile} is used.
133 * @return The ClassLoader. Returns null on an error.
134 */
135 private static ClassLoader tryCreatingClassLoader(
136 String canaryClassName, File dexFile, File optimizedDir) {
137 try {
138 ClassLoader loader = new BaseDexClassLoader(
139 dexFile.getPath(), optimizedDir, null, ClassLoader.getSystem ClassLoader());
140 // Loading {@link canaryClassName} will throw an exception if the .d ex file cannot be
141 // loaded.
142 loader.loadClass(canaryClassName);
143 return loader;
144 } catch (Exception e) {
145 String optimizedDirPath = (optimizedDir == null) ? null : optimizedD ir.getPath();
146 Log.w(TAG, "Could not load dex from " + dexFile.getPath() + " with o ptimized directory "
147 + optimizedDirPath);
148 e.printStackTrace();
149 return null;
150 }
151 }
152 }
OLDNEW
« no previous file with comments | « chrome/android/webapk/shell_apk/javatests/src/org/chromium/webapk/shell_apk/DexLoaderTest.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698