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

Side by Side Diff: web_apks/minting_example/src/org/chromium/minting/MintingApplication.java

Issue 1710083004: Support Crazy Linker in WebAPK to load Chrome's uncompressed native libraries. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.minting; 5 package org.chromium.minting;
6 6
7 import android.app.Application; 7 import android.app.Application;
8 import android.content.Context; 8 import android.content.Context;
9 import android.content.pm.PackageManager.NameNotFoundException; 9 import android.content.pm.PackageManager.NameNotFoundException;
10 import android.util.Log; 10 import android.util.Log;
11 11
12 import java.io.File;
13 import java.lang.reflect.Array; 12 import java.lang.reflect.Array;
14 import java.lang.reflect.Field; 13 import java.util.List;
15 14
16 /** 15 /**
17 * Example application for a minted APK. 16 * Example application for a minted APK.
18 */ 17 */
19 public class MintingApplication extends Application { 18 public class MintingApplication extends Application {
20 static final String CHROME_PACKAGE_PREF = "CHROME_PACKAGE_PREF"; 19 static final String CHROME_PACKAGE_PREF = "CHROME_PACKAGE_PREF";
21 static final String MINT_PREFS = "MINT_PREFS"; 20 static final String MINT_PREFS = "MINT_PREFS";
22 static final String DEFAULT_CHROME_PACKAGE_NAME = "com.google.android.apps.c hrome"; 21 static final String DEFAULT_CHROME_PACKAGE_NAME = "com.google.android.apps.c hrome";
23 22
24 // Context of Chrome. 23 // Context of Chrome.
25 private Context mRemoteContext = null; 24 private Context mRemoteContext = null;
26 25
27 private static final String TAG = "cr.MintingApplication"; 26 private static final String TAG = "cr.MintingApplication";
28 private static final String SECONDARY_FOLDER_NAME = "code_cache" + File.sepa rator
29 + "secondary-dexes";
30
31 private static Field findField(Object instance, String name) throws NoSuchFi eldException {
32 for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz. getSuperclass()) {
33 try {
34 Field field = clazz.getDeclaredField(name);
35 if (!field.isAccessible()) {
36 field.setAccessible(true);
37 }
38 return field;
39 } catch (NoSuchFieldException e) {
40 // ignore and search next
41 }
42 }
43 throw new NoSuchFieldException("Field " + name + " not found in " + inst ance.getClass());
44 }
45
46 /** 27 /**
47 * Copy all the objects from a specified field of the second instance to the same field of the 28 * Copy all the objects from a specified field of the hostInstance to the sa me field of the
48 * first instance. As a result, the given field of the first instance will c ontain all the 29 * mintInstance. As a result, the given field of the mintInstance will conta in all the
49 * objects from both instances. 30 * objects from both instances.
50 * @param instance the first instance which contains a field of the given fi eldName. 31 * @param mintInstance the first instance which contains a field of the give n fieldName.
51 * @param fieldName the name of field to expand to an Object array. 32 * @param fieldName the name of field to expand to an Object array.
52 * @param instance2 the second instance which has a field of the given field Name. 33 * @param hostInstance the second instance which has a field of the given fi eldName.
53 * @throws NoSuchFieldException 34 * @throws NoSuchFieldException
54 * @throws IllegalArgumentException 35 * @throws IllegalArgumentException
55 * @throws IllegalAccessException 36 * @throws IllegalAccessException
56 */ 37 */
57 private static void expandFieldArray(Object instance, String fieldName, 38 private static void expandField(Object mintInstance, String fieldName, Objec t hostInstance)
58 Object instance2) throws NoSuchFieldException, IllegalArgumentExcept ion, 39 throws NoSuchFieldException, IllegalArgumentException,
59 IllegalAccessException { 40 IllegalAccessException {
60 Field jlrField = findField(instance, fieldName); 41 try {
61 Object[] original = (Object[]) jlrField.get(instance); 42 Object hostCurrentDirs = Reflect.getField(hostInstance, fieldName);
62 Object[] additional = (Object[]) jlrField.get(instance2); 43 Object mintCurrentDirs = Reflect.getField(mintInstance, fieldName);
63 Object[] combined = (Object[]) Array.newInstance( 44 // Switched from an array to an ArrayList in Lollipop.
64 original.getClass().getComponentType(), original.length + additi onal.length); 45 if (mintCurrentDirs instanceof List) {
65 System.arraycopy(original, 0, combined, 0, original.length); 46 List<Object> mintDirsAsList = (List<Object>) mintCurrentDirs;
66 System.arraycopy(additional, 0, combined, original.length, additional.le ngth); 47 concatAndRemoveEndDuplicates(mintDirsAsList, (List<Object>) host CurrentDirs);
Yaron 2016/02/19 22:10:20 Are the duplicates a concern? Are they not just ig
Xi Han 2016/02/24 19:09:38 If simply inserting the Chrome's array before WebA
Yaron 2016/02/25 05:32:50 Perhaps you're reight and we shouldn't have the /v
67 jlrField.set(instance, combined); 48 List<Object> combined = (List<Object>) Reflect.getField(mintInst ance, fieldName);
49 for (Object o: combined) {
Yaron 2016/02/19 22:10:20 nit: the previous line and this section are just f
Xi Han 2016/02/24 19:09:38 Done.
Yaron 2016/02/25 05:32:50 You can also get rid of Reflect.getField from both
Xi Han 2016/02/25 14:55:38 Good catch, removed.
50 Log.w(TAG, "element in the path of " + fieldName + " : " + o .toString());
51 }
52 } else {
53 Object[] mintDirsAsArray = (Object[]) mintCurrentDirs;
54 Object[] hostDirsAsArray = (Object[]) hostCurrentDirs;
55 Reflect.setField(mintInstance, fieldName,
56 concatAndRemoveEndDuplicates(mintDirsAsArray, hostDirsAs Array));
57 Object[] combined = (Object[]) Reflect.getField(mintInstance, fi eldName);
58 for (Object o: combined) {
59 Log.w(TAG, "element in the path of " + fieldName + ": " + o. toString());
60 }
61 }
62 } catch (ReflectiveOperationException e) {
63 e.printStackTrace();
64 }
68 } 65 }
69 66
70 private void addExternalLoader() { 67 /**
68 * Combines two arrays into a new array.
69 * If the two arrays end with duplicated elements, keep one copy only. For e xample,
70 * the first array is [A, B, C, D], and the second array is [E, F, C, D], th e combined one is
71 * [A, B, E, F, C, D]. The unique elements are stored before the duplicates.
72 * The arrays must be of the same type.
73 * @param mintArrays: the array from a WebAPK
74 * @param hostArrays: the array from the host
75 * @return: a combined array consists of [WebAPK unique elements, host's uni que elements,
76 * duplicated one]
77 */
78 private static Object[] concatAndRemoveEndDuplicates(Object[] mintArrays, Ob ject[] hostArrays) {
79 int duplicate1 = mintArrays.length - 1;
80 int duplicate2 = hostArrays.length - 1;
81 int count = 0;
82 while (duplicate1 >= 0 && duplicate2 >= 0
83 && mintArrays[duplicate1].toString().equals(hostArrays[duplicate 2].toString())) {
84 --duplicate1;
85 --duplicate2;
86 ++count;
87 }
88 Object[] combined = (Object[]) Array.newInstance(mintArrays.getClass().g etComponentType(),
89 mintArrays.length + hostArrays.length - count);
90 if (mintArrays.length - count > 0) {
91 System.arraycopy(mintArrays, 0, combined, 0, mintArrays.length - cou nt);
92 }
93 System.arraycopy(hostArrays, 0, combined, mintArrays.length - count, hos tArrays.length);
94 return combined;
95 }
96
97 /**
98 * Add the unique elements of the second list to the first one.
99 * If the two lists end with duplicated elements, keep one copy only. For ex ample,
100 * the first list is [A, B, C, D], and the second list is [E, F, C, D], the combined one is
101 * [A, B, E, F, C, D]. The unique elements are store before the duplicates.
102 * The lists must be of the same type.
103 * @param mintList: the list from a WebAPK
104 * @param hostList: the list from the host
105 * @return: a combined list consists of [WebAPK unique elements, host's uniq ue elements,
106 * duplicated one]
107 */
108 private static void concatAndRemoveEndDuplicates(List<Object> mintList, List <Object> hostList) {
109 int duplicate1 = mintList.size() - 1;
110 int duplicate2 = hostList.size() - 1;
111 while (duplicate1 >= 0 && duplicate2 >= 0
112 && mintList.get(duplicate1).toString().equals(hostList.get(dupli cate2).toString()))
113 {
114 --duplicate1;
115 --duplicate2;
116 }
117 for (int i = 0; i < duplicate2 + 1; i++) {
118 mintList.add(duplicate1 + i, hostList.get(i));
119 }
120 }
121
122 private void addExternalLoader() throws ReflectiveOperationException {
71 if (mRemoteContext == null) { 123 if (mRemoteContext == null) {
72 Log.w(TAG, "Failed to add external loader since the remote context i s null."); 124 Log.w(TAG, "Failed to add external loader since the remote context i s null.");
73 return; 125 return;
74 } 126 }
75 ClassLoader externalLoader = mRemoteContext.getClassLoader(); 127 ClassLoader externalLoader = mRemoteContext.getClassLoader();
76 ClassLoader mintLoader = getClassLoader(); 128 ClassLoader mintLoader = getClassLoader();
77 129
78 try { 130 Object extDexPathList = Reflect.getField(externalLoader, "pathList");
79 Field field = findField(externalLoader, "pathList"); 131 Object mintDexPathList = Reflect.getField(mintLoader, "pathList");
80 Object dexOriginal = field.get(mintLoader); 132 expandField(mintDexPathList, "dexElements", extDexPathList);
81 Object dexAdditional = field.get(externalLoader); 133 }
82 expandFieldArray(dexOriginal, "dexElements", dexAdditional); 134
83 } catch (NoSuchFieldException | IllegalAccessException | IllegalArgument Exception e1) { 135 private void addNativeLibrarySearchPath() throws ReflectiveOperationExceptio n {
84 e1.printStackTrace(); 136 if (mRemoteContext == null) {
85 throw new RuntimeException(e1); 137 Log.w(TAG, "Failed to add external loader since the remote context i s null.");
138 return;
86 } 139 }
140 ClassLoader externalLoader = mRemoteContext.getClassLoader();
141 ClassLoader mintLoader = getClassLoader();
142
143 // Since both WebAPK and its host have the "system/lib" and "vendor/lib" at the end of
144 // the native library directory path list, we want to add host's directo ries before the
145 // system directory, and only keep one copy of the system directories.
146 // This is because when System.loadLibrary() is called, we want it searc h the host's
147 // native library directories first. If a ".so" file doesn't exit, then search /system/lib.
148 Object extDexPathList = Reflect.getField(externalLoader, "pathList");
149 Object mintDexPathList = Reflect.getField(mintLoader, "pathList");
150 expandField(mintDexPathList, "nativeLibraryDirectories", extDexPathList) ;
151 expandField(mintDexPathList, "nativeLibraryPathElements", extDexPathList );
87 } 152 }
88 153
89 @Override 154 @Override
90 public void onCreate() { 155 public void onCreate() {
91 super.onCreate(); 156 super.onCreate();
92 try { 157 try {
93 String packageString = getSharedPreferences(MINT_PREFS, MODE_PRIVATE ) 158 String packageString = getSharedPreferences(MINT_PREFS, MODE_PRIVATE )
94 .getString(CHROME_PACKAGE_PREF, DEFAULT_CHROME_PACKAGE_NAME) ; 159 .getString(CHROME_PACKAGE_PREF, DEFAULT_CHROME_PACKAGE_NAME) ;
95 Log.w(TAG, "Getting remote context for package " + packageString); 160 Log.w(TAG, "Getting remote context for package " + packageString);
96 mRemoteContext = getApplicationContext().createPackageContext( 161 mRemoteContext = getApplicationContext().createPackageContext(
97 packageString, 162 packageString,
98 Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CO DE); 163 Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CO DE);
99 addExternalLoader(); 164 try {
165 addExternalLoader();
166 addNativeLibrarySearchPath();
167 } catch (ReflectiveOperationException e) {
168 e.printStackTrace();
169 }
100 Log.w(TAG, "Successfully add external loader."); 170 Log.w(TAG, "Successfully add external loader.");
101 } catch (NameNotFoundException e) { 171 } catch (NameNotFoundException e) {
102 e.printStackTrace(); 172 e.printStackTrace();
103 } 173 }
104 } 174 }
105 } 175 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698