10
10
import java .io .InputStreamReader ;
11
11
import java .io .InvalidClassException ;
12
12
import java .io .OutputStreamWriter ;
13
- import java .lang .reflect .InvocationTargetException ;
14
- import java .util .ArrayList ;
13
+ import java .util .HashMap ;
15
14
import java .util .HashSet ;
16
- import java .util .List ;
15
+ import java .util .zip .ZipEntry ;
16
+ import java .util .zip .ZipOutputStream ;
17
17
18
18
import com .tns .bindings .ProxyGenerator ;
19
- import com .tns .multidex .MultiDex ;
20
19
20
+ import dalvik .system .DexClassLoader ;
21
21
import android .content .Context ;
22
22
import android .content .pm .ApplicationInfo ;
23
23
import android .content .pm .PackageInfo ;
26
26
27
27
public class DexFactory
28
28
{
29
- private Context context ;
30
-
31
29
private static final String SECONDARY_DEX_FOLDER_NAME = "code_cache" + File .separator + "secondary-dexes" ;
32
30
33
- private String proxyPath ;
31
+ private String dexPath ;
32
+ private String odexPath ;
33
+ private String dexThumb ;
34
+ private Context context ;
34
35
35
36
private ProxyGenerator proxyGenerator ;
36
-
37
- private File odexDir ;
38
-
39
- private HashSet <String > injectedProxyClasses = new HashSet <String >();
37
+ private HashMap <String , Class <?>> injectedDexClasses = new HashMap <String , Class <?>>();
40
38
41
- private String proxyThumb ;
42
-
43
39
public DexFactory (Context context )
44
40
{
45
41
this .context = context ;
46
42
47
- ApplicationInfo applicationInfo = context .getApplicationInfo ();
48
- proxyPath = applicationInfo .dataDir + File .separator + SECONDARY_DEX_FOLDER_NAME + File .separator ;
49
- proxyGenerator = new ProxyGenerator (proxyPath );
43
+ ApplicationInfo applicationInfo = this .context .getApplicationInfo ();
44
+ this .dexPath = applicationInfo .dataDir + File .separator + SECONDARY_DEX_FOLDER_NAME + File .separator ;
45
+ this .odexPath = this .dexPath + "odex" + File .separator ;
46
+ this .proxyGenerator = new ProxyGenerator (dexPath );
50
47
ProxyGenerator .IsLogEnabled = Platform .IsLogEnabled ;
51
- File dexDir = new File ( proxyPath );
52
- odexDir = new File (dexDir . getAbsolutePath () + File . separator + "odex" + File . separator );
48
+
49
+ File odexDir = new File (this . odexPath );
53
50
odexDir .mkdirs ();
54
-
55
- updateProxyThumbAndPurgeCachedProxies ( dexDir );
56
- proxyGenerator .setProxyThumb (proxyThumb );
51
+
52
+ this . updateDexThumbAndPurgeCache ( );
53
+ this . proxyGenerator .setProxyThumb (this . dexThumb );
57
54
}
58
55
59
56
static long totalGenTime = 0 ;
@@ -62,92 +59,79 @@ public DexFactory(Context context)
62
59
63
60
public Class <?> resolveClass (String name , String className , String [] methodOverrides ) throws ClassNotFoundException , IOException
64
61
{
62
+ if (className .contains ("NativeScriptActivity" ))
63
+ {
64
+ // Do not extend NativeScriptActivity - it is already extended
65
+ return NativeScriptActivity .class ;
66
+ }
67
+
65
68
String fullClassName = className .replace ("$" , "_" ) + "-" + name ;
66
-
67
- if (! injectedProxyClasses . contains ( fullClassName ) )
69
+ Class <?> existingClass = this . injectedDexClasses . get ( fullClassName );
70
+ if ( existingClass != null )
68
71
{
69
- File proxyFile = getProxyFile (fullClassName );
70
-
71
- if (proxyFile == null )
72
- {
73
- long startGenTime = System .nanoTime ();
74
- String proxyFilePath = "" ;
75
-
76
- if (Platform .IsLogEnabled )
77
- {
78
- Log .d (Platform .DEFAULT_LOG_TAG , "generating proxy in place" );
79
- }
80
- proxyFilePath = generateProxy (name , className , methodOverrides );
81
- proxyFile = new File (proxyFilePath );
82
- long stopGenTime = System .nanoTime ();
83
- totalGenTime += stopGenTime - startGenTime ;
84
- if (Platform .IsLogEnabled )
85
- {
86
- Log .d (Platform .DEFAULT_LOG_TAG , "Finished inplace gen took: " + (stopGenTime - startGenTime ) / 1000000.0 + "ms" );
87
- Log .d (Platform .DEFAULT_LOG_TAG , "TotalGenTime: " + totalGenTime / 1000000.0 + "ms" );
88
- }
89
- }
72
+ return existingClass ;
73
+ }
90
74
91
- long startMultiDexTime = System .nanoTime ();
92
- List <File > files = new ArrayList <File >();
93
- files .add (proxyFile );
94
- try
95
- {
96
- MultiDex .installSecondaryDexes (context .getClassLoader (), odexDir , files );
97
- injectedProxyClasses .add (fullClassName );
98
- }
99
- catch (IllegalArgumentException e )
100
- {
101
- e .printStackTrace ();
102
- }
103
- catch (IllegalAccessException e )
104
- {
105
- e .printStackTrace ();
106
- }
107
- catch (NoSuchFieldException e )
108
- {
109
- e .printStackTrace ();
110
- }
111
- catch (InvocationTargetException e )
112
- {
113
- e .printStackTrace ();
114
- }
115
- catch (NoSuchMethodException e )
116
- {
117
- e .printStackTrace ();
118
- }
119
- long stopMultiDexTime = System .nanoTime ();
120
- totalMultiDexTime += (stopMultiDexTime - startMultiDexTime );
75
+ String classToProxy = this .getClassToProxyName (className );
76
+ String dexFilePath = classToProxy + "-" + name ;
77
+ File dexFile = this .getDexFile (dexFilePath );
78
+
79
+ if (dexFile == null )
80
+ {
81
+ long startGenTime = System .nanoTime ();
121
82
if (Platform .IsLogEnabled )
122
83
{
123
- Log .d (Platform .DEFAULT_LOG_TAG , "Finished injecting into multidex: " + proxyFile .getAbsolutePath () + " took: " + (stopMultiDexTime - startMultiDexTime ) / 1000000.0 + "ms" );
124
- Log .d (Platform .DEFAULT_LOG_TAG , "TotalMultiDexTime: " + totalMultiDexTime / 1000000.0 + "ms" );
84
+ Log .d (Platform .DEFAULT_LOG_TAG , "generating proxy in place" );
125
85
}
126
-
127
-
128
- long startLoadDexTime = System .nanoTime ();
129
- // String classToProxyName = className.replace("$", "_");
130
- // className = classToProxyName;
131
-
132
- Class <?> loaded = context .getClassLoader ().loadClass (fullClassName );
133
- long stopLoadDexTime = System .nanoTime ();
134
- totalLoadDexTime += (stopLoadDexTime - startLoadDexTime );
86
+
87
+ dexFilePath = this .generateDex (name , classToProxy , methodOverrides );
88
+ dexFile = new File (dexFilePath );
89
+ long stopGenTime = System .nanoTime ();
90
+ totalGenTime += stopGenTime - startGenTime ;
135
91
if (Platform .IsLogEnabled )
136
92
{
137
- Log .d (Platform .DEFAULT_LOG_TAG , "Finished loading class : " + fullClassName + " took: " + (stopMultiDexTime - startMultiDexTime ) / 1000000.0 + "ms" );
138
- Log .d (Platform .DEFAULT_LOG_TAG , "TotalLoadDexTime: " + totalLoadDexTime / 1000000.0 + "ms" );
93
+ Log .d (Platform .DEFAULT_LOG_TAG , "Finished inplace gen took: " + (stopGenTime - startGenTime ) / 1000000.0 + "ms" );
94
+ Log .d (Platform .DEFAULT_LOG_TAG , "TotalGenTime: " + totalGenTime / 1000000.0 + "ms" );
139
95
}
96
+ }
97
+
98
+ String jarFilePath = dexFile .getPath ().replace (".dex" , ".jar" );
99
+ File jarFile = new File (jarFilePath );
100
+
101
+ Class <?> result ;
102
+ if (!jarFile .exists ())
103
+ {
104
+ FileOutputStream jarFileStream = new FileOutputStream (jarFile );
140
105
141
- return loaded ;
106
+ ZipOutputStream out = new ZipOutputStream (jarFileStream );
107
+ out .putNextEntry (new ZipEntry ("classes.dex" ));
108
+ byte [] dexData = new byte [(int )dexFile .length ()];
109
+ FileInputStream fi = new FileInputStream (dexFile );
110
+ fi .read (dexData , 0 , dexData .length );
111
+ fi .close ();
112
+ out .write (dexData );
113
+ out .closeEntry ();
114
+ out .close ();
115
+
142
116
}
143
-
144
- return findClass (fullClassName );
117
+
118
+ DexClassLoader dexClassLoader = new DexClassLoader (jarFilePath , this .odexPath , null , this .context .getClassLoader ());
119
+ result = dexClassLoader .loadClass (fullClassName );
120
+
121
+ this .injectedDexClasses .put (fullClassName , result );
122
+
123
+ return result ;
145
124
}
146
125
147
126
public Class <?> findClass (String className ) throws ClassNotFoundException
148
127
{
149
128
String canonicalName = className .replace ('/' , '.' );
150
- return context .getClassLoader ().loadClass (canonicalName );
129
+ Class <?> existingClass = this .injectedDexClasses .get (canonicalName );
130
+ if (existingClass != null )
131
+ {
132
+ return existingClass ;
133
+ }
134
+ return this .context .getClassLoader ().loadClass (canonicalName );
151
135
}
152
136
153
137
public static String strJoin (String [] array , String separator )
@@ -168,8 +152,8 @@ public static String strJoin(String[] array, String separator)
168
152
}
169
153
return sbStr .toString ();
170
154
}
171
-
172
- private File getProxyFile (String className ) throws InvalidClassException
155
+
156
+ private String getClassToProxyName (String className ) throws InvalidClassException
173
157
{
174
158
String classToProxy = className ;
175
159
@@ -182,46 +166,40 @@ private File getProxyFile(String className) throws InvalidClassException
182
166
{
183
167
throw new InvalidClassException ("Can't generate proxy of proxy" );
184
168
}
169
+
170
+ return classToProxy ;
171
+ }
185
172
186
- String classToProxyFile = classToProxy .replace ("$" , "_" );
173
+ private File getDexFile (String className ) throws InvalidClassException
174
+ {
175
+ String classToProxyFile = className .replace ("$" , "_" );
187
176
188
- if (proxyThumb != null )
177
+ if (this . dexThumb != null )
189
178
{
190
- classToProxyFile += "-" + proxyThumb ;
179
+ classToProxyFile += "-" + this . dexThumb ;
191
180
}
192
181
193
- String proxyFilePath = proxyPath + classToProxyFile + ".dex" ;
194
- File proxyFile = new File (proxyFilePath );
195
- if (proxyFile .exists ())
182
+ String dexFilePath = dexPath + classToProxyFile + ".dex" ;
183
+ File dexFile = new File (dexFilePath );
184
+ if (dexFile .exists ())
196
185
{
197
186
if (Platform .IsLogEnabled )
198
187
{
199
- Log .d (Platform .DEFAULT_LOG_TAG , "Looking for proxy file: " + proxyFilePath + " Result: proxy file Found. ClassName: " + className );
188
+ Log .d (Platform .DEFAULT_LOG_TAG , "Looking for proxy file: " + dexFilePath + " Result: proxy file Found. ClassName: " + className );
200
189
}
201
- return proxyFile ;
190
+ return dexFile ;
202
191
}
203
192
204
193
if (Platform .IsLogEnabled )
205
194
{
206
- Log .d (Platform .DEFAULT_LOG_TAG , "Looking for proxy file: " + proxyFilePath + " Result: NOT Found. Proxy Gen needed. ClassName: " + className );
195
+ Log .d (Platform .DEFAULT_LOG_TAG , "Looking for proxy file: " + dexFilePath + " Result: NOT Found. Proxy Gen needed. ClassName: " + className );
207
196
}
208
197
return null ;
209
198
}
210
199
211
- private String generateProxy (String proxyName , String className , String [] methodOverrides ) throws ClassNotFoundException , IOException
200
+ private String generateDex (String proxyName , String className , String [] methodOverrides ) throws ClassNotFoundException , IOException
212
201
{
213
- String classToProxyName = className ;
214
- if (className .startsWith ("com.tns.gen." ))
215
- {
216
- classToProxyName = className .substring (12 );
217
- }
218
-
219
- if (classToProxyName .startsWith ("com.tns.gen." ))
220
- {
221
- throw new InvalidClassException ("Can't generate proxy of proxy" );
222
- }
223
-
224
- Class <?> classToProxy = Class .forName (classToProxyName );
202
+ Class <?> classToProxy = Class .forName (className );
225
203
226
204
HashSet <String > methodOverridesSet = null ;
227
205
if (methodOverrides != null )
@@ -237,43 +215,46 @@ private String generateProxy(String proxyName, String className, String[] method
237
215
return proxyGenerator .generateProxy (proxyName , classToProxy , methodOverridesSet );
238
216
}
239
217
240
- private void updateProxyThumbAndPurgeCachedProxies ( File proxyDir )
218
+ private void updateDexThumbAndPurgeCache ( )
241
219
{
242
- proxyThumb = generateProxyThumb ();
243
- if (proxyThumb == null )
220
+ this . dexThumb = this . generateDexThumb ();
221
+ if (this . dexThumb == null )
244
222
{
245
223
throw new RuntimeException ("Error generating proxy thumb 1" );
246
224
}
247
225
248
- String oldProxyThumb = getCachedProxyThumb (proxyDir );
249
- if (proxyThumb .equals (oldProxyThumb ))
226
+ File dexDir = new File (this .dexPath );
227
+ String oldDexThumb = this .getCachedProxyThumb (dexDir );
228
+ if (this .dexThumb .equals (oldDexThumb ))
250
229
{
251
230
return ;
252
231
}
253
232
254
- if (oldProxyThumb != null )
233
+ if (oldDexThumb != null )
255
234
{
256
- purgeProxiesByThumb (oldProxyThumb , proxyDir );
235
+ this .purgeDexesByThumb (oldDexThumb , dexDir );
236
+ this .purgeDexesByThumb (oldDexThumb , new File (odexPath ));
257
237
}
258
238
else
259
239
{
260
- //purge all dex files in proxy dir if no thumg file is found
261
- purgeProxiesByThumb (".dex" , proxyDir );
240
+ //purge all dex files if no thumb file is found
241
+ this .purgeDexesByThumb (null , dexDir );
242
+ this .purgeDexesByThumb (null , new File (odexPath ));
262
243
}
263
244
264
- saveNewProxyThumb ( proxyThumb , proxyDir );
245
+ this . saveNewDexThumb ( this . dexThumb , dexDir );
265
246
}
266
247
267
- private void saveNewProxyThumb (String newProxyThumb , File proxyDir )
248
+ private void saveNewDexThumb (String newDexThumb , File dexDir )
268
249
{
269
- File cachedThumbFile = new File (proxyDir , "proxyThumb" );
250
+ File cachedThumbFile = new File (dexDir , "proxyThumb" );
270
251
try
271
252
{
272
253
FileOutputStream out = new FileOutputStream (cachedThumbFile , false );
273
254
BufferedWriter writer = new BufferedWriter (new OutputStreamWriter (out ));
274
255
try
275
256
{
276
- writer .write (newProxyThumb );
257
+ writer .write (newDexThumb );
277
258
writer .newLine ();
278
259
writer .flush ();
279
260
}
@@ -295,7 +276,7 @@ private void saveNewProxyThumb(String newProxyThumb, File proxyDir)
295
276
}
296
277
}
297
278
298
- private String generateProxyThumb ()
279
+ private String generateDexThumb ()
299
280
{
300
281
try
301
282
{
@@ -313,7 +294,7 @@ private String generateProxyThumb()
313
294
return null ;
314
295
}
315
296
316
- private void purgeProxiesByThumb (String cachedproxyThumb , File pathToPurge )
297
+ private void purgeDexesByThumb (String cachedDexThumb , File pathToPurge )
317
298
{
318
299
if (!pathToPurge .isDirectory ())
319
300
{
@@ -328,13 +309,13 @@ private void purgeProxiesByThumb(String cachedproxyThumb, File pathToPurge)
328
309
File purgeCandidate = new File (pathToPurge , filename );
329
310
if (purgeCandidate .isDirectory ())
330
311
{
331
- purgeProxiesByThumb ( cachedproxyThumb , purgeCandidate );
312
+ this . purgeDexesByThumb ( cachedDexThumb , purgeCandidate );
332
313
}
333
314
else
334
315
{
335
- if (! filename .contains (cachedproxyThumb ))
316
+ if (cachedDexThumb != null && ! filename .contains (cachedDexThumb ))
336
317
{
337
- return ;
318
+ continue ;
338
319
}
339
320
340
321
boolean b = purgeCandidate .delete ();
@@ -374,4 +355,4 @@ private String getCachedProxyThumb(File proxyDir)
374
355
375
356
return null ;
376
357
}
377
- }
358
+ }
0 commit comments