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

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: nits Created 4 years, 9 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);
67 jlrField.set(instance, combined); 48 } else {
49 Object[] mintDirsAsArray = (Object[]) mintCurrentDirs;
50 Object[] hostDirsAsArray = (Object[]) hostCurrentDirs;
51 Reflect.setField(mintInstance, fieldName,
52 concatAndRemoveEndDuplicates(mintDirsAsArray, hostDirsAs Array));
53 }
54 } catch (ReflectiveOperationException e) {
55 e.printStackTrace();
56 }
68 } 57 }
69 58
70 private void addExternalLoader() { 59 /**
60 * Combines two arrays into a new array.
61 * If the two arrays end with duplicated elements, keep one copy only. For e xample,
62 * the first array is [A, B, C, D], and the second array is [E, F, C, D], th e combined one is
63 * [A, B, E, F, C, D]. The unique elements are stored before the duplicates.
64 * The arrays must be of the same type.
65 * @param mintArrays: the array from a WebAPK
66 * @param hostArrays: the array from the host
67 * @return: a combined array consists of [WebAPK unique elements, host's uni que elements,
68 * duplicated one]
69 */
70 private static Object[] concatAndRemoveEndDuplicates(Object[] mintArrays, Ob ject[] hostArrays) {
71 int duplicate1 = mintArrays.length - 1;
72 int duplicate2 = hostArrays.length - 1;
73 int count = 0;
74 while (duplicate1 >= 0 && duplicate2 >= 0
75 && mintArrays[duplicate1].toString().equals(hostArrays[duplicate 2].toString())) {
76 --duplicate1;
77 --duplicate2;
78 ++count;
79 }
80 Object[] combined = (Object[]) Array.newInstance(mintArrays.getClass().g etComponentType(),
81 mintArrays.length + hostArrays.length - count);
82 if (mintArrays.length - count > 0) {
83 System.arraycopy(mintArrays, 0, combined, 0, mintArrays.length - cou nt);
84 }
85 System.arraycopy(hostArrays, 0, combined, mintArrays.length - count, hos tArrays.length);
86 return combined;
87 }
88
89 /**
90 * Add the unique elements of the second list to the first one.
91 * If the two lists end with duplicated elements, keep one copy only. For ex ample,
92 * the first list is [A, B, C, D], and the second list is [E, F, C, D], the combined one is
93 * [A, B, E, F, C, D]. The unique elements are store before the duplicates.
94 * The lists must be of the same type.
95 * @param mintList: the list from a WebAPK
96 * @param hostList: the list from the host
97 * @return: a combined list consists of [WebAPK unique elements, host's uniq ue elements,
98 * duplicated one]
99 */
100 private static void concatAndRemoveEndDuplicates(List<Object> mintList, List <Object> hostList) {
101 int duplicate1 = mintList.size() - 1;
102 int duplicate2 = hostList.size() - 1;
103 while (duplicate1 >= 0 && duplicate2 >= 0
104 && mintList.get(duplicate1).toString().equals(hostList.get(dupli cate2).toString()))
105 {
106 --duplicate1;
107 --duplicate2;
108 }
109 for (int i = 0; i < duplicate2 + 1; i++) {
110 mintList.add(duplicate1 + i, hostList.get(i));
111 }
112 }
113
114 private void addExternalLoader() throws ReflectiveOperationException {
71 if (mRemoteContext == null) { 115 if (mRemoteContext == null) {
72 Log.w(TAG, "Failed to add external loader since the remote context i s null."); 116 Log.w(TAG, "Failed to add external loader since the remote context i s null.");
73 return; 117 return;
74 } 118 }
75 ClassLoader externalLoader = mRemoteContext.getClassLoader(); 119 ClassLoader externalLoader = mRemoteContext.getClassLoader();
76 ClassLoader mintLoader = getClassLoader(); 120 ClassLoader mintLoader = getClassLoader();
77 121
78 try { 122 Object extDexPathList = Reflect.getField(externalLoader, "pathList");
79 Field field = findField(externalLoader, "pathList"); 123 Object mintDexPathList = Reflect.getField(mintLoader, "pathList");
80 Object dexOriginal = field.get(mintLoader); 124 expandField(mintDexPathList, "dexElements", extDexPathList);
81 Object dexAdditional = field.get(externalLoader); 125 }
82 expandFieldArray(dexOriginal, "dexElements", dexAdditional); 126
83 } catch (NoSuchFieldException | IllegalAccessException | IllegalArgument Exception e1) { 127 private void addNativeLibrarySearchPath() throws ReflectiveOperationExceptio n {
84 e1.printStackTrace(); 128 if (mRemoteContext == null) {
85 throw new RuntimeException(e1); 129 Log.w(TAG, "Failed to add external loader since the remote context i s null.");
130 return;
86 } 131 }
132 ClassLoader externalLoader = mRemoteContext.getClassLoader();
133 ClassLoader mintLoader = getClassLoader();
134
135 // Since both WebAPK and its host have the "system/lib" and "vendor/lib" at the end of
136 // the native library directory path list, we want to add host's directo ries before the
137 // system directory, and only keep one copy of the system directories.
138 // This is because when System.loadLibrary() is called, we want it searc h the host's
139 // native library directories first. If a ".so" file doesn't exit, then search /system/lib.
140 Object extDexPathList = Reflect.getField(externalLoader, "pathList");
141 Object mintDexPathList = Reflect.getField(mintLoader, "pathList");
142 expandField(mintDexPathList, "nativeLibraryDirectories", extDexPathList) ;
143 expandField(mintDexPathList, "nativeLibraryPathElements", extDexPathList );
87 } 144 }
88 145
89 @Override 146 @Override
90 public void onCreate() { 147 public void onCreate() {
91 super.onCreate(); 148 super.onCreate();
92 try { 149 try {
93 String packageString = getSharedPreferences(MINT_PREFS, MODE_PRIVATE ) 150 String packageString = getSharedPreferences(MINT_PREFS, MODE_PRIVATE )
94 .getString(CHROME_PACKAGE_PREF, DEFAULT_CHROME_PACKAGE_NAME) ; 151 .getString(CHROME_PACKAGE_PREF, DEFAULT_CHROME_PACKAGE_NAME) ;
95 Log.w(TAG, "Getting remote context for package " + packageString); 152 Log.w(TAG, "Getting remote context for package " + packageString);
96 mRemoteContext = getApplicationContext().createPackageContext( 153 mRemoteContext = getApplicationContext().createPackageContext(
97 packageString, 154 packageString,
98 Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CO DE); 155 Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CO DE);
99 addExternalLoader(); 156 try {
157 addExternalLoader();
158 addNativeLibrarySearchPath();
159 } catch (ReflectiveOperationException e) {
160 e.printStackTrace();
161 }
100 Log.w(TAG, "Successfully add external loader."); 162 Log.w(TAG, "Successfully add external loader.");
101 } catch (NameNotFoundException e) { 163 } catch (NameNotFoundException e) {
102 e.printStackTrace(); 164 e.printStackTrace();
103 } 165 }
104 } 166 }
105 } 167 }
OLDNEW
« no previous file with comments | « build/android/rezip/RezipApk.java ('k') | web_apks/minting_example/src/org/chromium/minting/Reflect.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698