/* * * Apache License * Version 2.0, January 2004 * http://www.apache.org/licenses/ * * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION * * 1. Definitions. * * "License" shall mean the terms and conditions for use, reproduction, * and distribution as defined by Sections 1 through 9 of this document. * * "Licensor" shall mean the copyright owner or entity authorized by * the copyright owner that is granting the License. * * "Legal Entity" shall mean the union of the acting entity and all * other entities that control, are controlled by, or are under common * control with that entity. For the purposes of this definition, * "control" means (i) the power, direct or indirect, to cause the * direction or management of such entity, whether by contract or * otherwise, or (ii) ownership of fifty percent (50%) or more of the * outstanding shares, or (iii) beneficial ownership of such entity. * * "You" (or "Your") shall mean an individual or Legal Entity * exercising permissions granted by this License. * * "Source" form shall mean the preferred form for making modifications, * including but not limited to software source code, documentation * source, and configuration files. * * "Object" form shall mean any form resulting from mechanical * transformation or translation of a Source form, including but * not limited to compiled object code, generated documentation, * and conversions to other media types. * * "Work" shall mean the work of authorship, whether in Source or * Object form, made available under the License, as indicated by a * copyright notice that is included in or attached to the work * (an example is provided in the Appendix below). * * "Derivative Works" shall mean any work, whether in Source or Object * form, that is based on (or derived from) the Work and for which the * editorial revisions, annotations, elaborations, or other modifications * represent, as a whole, an original work of authorship. For the purposes * of this License, Derivative Works shall not include works that remain * separable from, or merely link (or bind by name) to the interfaces of, * the Work and Derivative Works thereof. * * "Contribution" shall mean any work of authorship, including * the original version of the Work and any modifications or additions * to that Work or Derivative Works thereof, that is intentionally * submitted to Licensor for inclusion in the Work by the copyright owner * or by an individual or Legal Entity authorized to submit on behalf of * the copyright owner. For the purposes of this definition, "submitted" * means any form of electronic, verbal, or written communication sent * to the Licensor or its representatives, including but not limited to * communication on electronic mailing lists, source code control systems, * and issue tracking systems that are managed by, or on behalf of, the * Licensor for the purpose of discussing and improving the Work, but * excluding communication that is conspicuously marked or otherwise * designated in writing by the copyright owner as "Not a Contribution." * * "Contributor" shall mean Licensor and any individual or Legal Entity * on behalf of whom a Contribution has been received by Licensor and * subsequently incorporated within the Work. * * 2. Grant of Copyright License. Subject to the terms and conditions of * this License, each Contributor hereby grants to You a perpetual, * worldwide, non-exclusive, no-charge, royalty-free, irrevocable * copyright license to reproduce, prepare Derivative Works of, * publicly display, publicly perform, sublicense, and distribute the * Work and such Derivative Works in Source or Object form. * * 3. Grant of Patent License. Subject to the terms and conditions of * this License, each Contributor hereby grants to You a perpetual, * worldwide, non-exclusive, no-charge, royalty-free, irrevocable * (except as stated in this section) patent license to make, have made, * use, offer to sell, sell, import, and otherwise transfer the Work, * where such license applies only to those patent claims licensable * by such Contributor that are necessarily infringed by their * Contribution(s) alone or by combination of their Contribution(s) * with the Work to which such Contribution(s) was submitted. If You * institute patent litigation against any entity (including a * cross-claim or counterclaim in a lawsuit) alleging that the Work * or a Contribution incorporated within the Work constitutes direct * or contributory patent infringement, then any patent licenses * granted to You under this License for that Work shall terminate * as of the date such litigation is filed. * * 4. Redistribution. You may reproduce and distribute copies of the * Work or Derivative Works thereof in any medium, with or without * modifications, and in Source or Object form, provided that You * meet the following conditions: * * (a) You must give any other recipients of the Work or * Derivative Works a copy of this License; and * * (b) You must cause any modified files to carry prominent notices * stating that You changed the files; and * * (c) You must retain, in the Source form of any Derivative Works * that You distribute, all copyright, patent, trademark, and * attribution notices from the Source form of the Work, * excluding those notices that do not pertain to any part of * the Derivative Works; and * * (d) If the Work includes a "NOTICE" text file as part of its * distribution, then any Derivative Works that You distribute must * include a readable copy of the attribution notices contained * within such NOTICE file, excluding those notices that do not * pertain to any part of the Derivative Works, in at least one * of the following places: within a NOTICE text file distributed * as part of the Derivative Works; within the Source form or * documentation, if provided along with the Derivative Works; or, * within a display generated by the Derivative Works, if and * wherever such third-party notices normally appear. The contents * of the NOTICE file are for informational purposes only and * do not modify the License. You may add Your own attribution * notices within Derivative Works that You distribute, alongside * or as an addendum to the NOTICE text from the Work, provided * that such additional attribution notices cannot be construed * as modifying the License. * * You may add Your own copyright statement to Your modifications and * may provide additional or different license terms and conditions * for use, reproduction, or distribution of Your modifications, or * for any such Derivative Works as a whole, provided Your use, * reproduction, and distribution of the Work otherwise complies with * the conditions stated in this License. * * 5. Submission of Contributions. Unless You explicitly state otherwise, * any Contribution intentionally submitted for inclusion in the Work * by You to the Licensor shall be under the terms and conditions of * this License, without any additional terms or conditions. * Notwithstanding the above, nothing herein shall supersede or modify * the terms of any separate license agreement you may have executed * with Licensor regarding such Contributions. * * 6. Trademarks. This License does not grant permission to use the trade * names, trademarks, service marks, or product names of the Licensor, * except as required for reasonable and customary use in describing the * origin of the Work and reproducing the content of the NOTICE file. * * 7. Disclaimer of Warranty. Unless required by applicable law or * agreed to in writing, Licensor provides the Work (and each * Contributor provides its Contributions) on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied, including, without limitation, any warranties or conditions * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A * PARTICULAR PURPOSE. You are solely responsible for determining the * appropriateness of using or redistributing the Work and assume any * risks associated with Your exercise of permissions under this License. * * 8. Limitation of Liability. In no event and under no legal theory, * whether in tort (including negligence), contract, or otherwise, * unless required by applicable law (such as deliberate and grossly * negligent acts) or agreed to in writing, shall any Contributor be * liable to You for damages, including any direct, indirect, special, * incidental, or consequential damages of any character arising as a * result of this License or out of the use or inability to use the * Work (including but not limited to damages for loss of goodwill, * work stoppage, computer failure or malfunction, or any and all * other commercial damages or losses), even if such Contributor * has been advised of the possibility of such damages. * * 9. Accepting Warranty or Additional Liability. While redistributing * the Work or Derivative Works thereof, You may choose to offer, * and charge a fee for, acceptance of support, warranty, indemnity, * or other liability obligations and/or rights consistent with this * License. However, in accepting such obligations, You may act only * on Your own behalf and on Your sole responsibility, not on behalf * of any other Contributor, and only if You agree to indemnify, * defend, and hold each Contributor harmless for any liability * incurred by, or claims asserted against, such Contributor by reason * of your accepting any such warranty or additional liability. * * END OF TERMS AND CONDITIONS * * APPENDIX: How to apply the Apache License to your work. * * To apply the Apache License to your work, attach the following * boilerplate notice, with the fields enclosed by brackets "[]" * replaced with your own identifying information. (Don't include * the brackets!) The text should be enclosed in the appropriate * comment syntax for the file format. We also recommend that a * file or class name and description of purpose be included on the * same "printed page" as the copyright notice for easier * identification within third-party archives. * * Copyright 2016 Alibaba Group * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * */ package android.taobao.atlas.startup.patch; import android.app.Application; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.os.Build; import android.taobao.atlas.startup.AtlasBridgeApplication; import android.taobao.atlas.startup.KernalVersionManager; import android.taobao.atlas.startup.NClassLoader; import android.text.TextUtils; import android.util.Log; import dalvik.system.DexFile; import dalvik.system.PathClassLoader; import java.io.*; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * Created by guanjie on 15/6/4. */ public class KernalBundle{ /** * the storage location. */ final File bundleDir; /** * the bundle archive file. */ KernalBundleArchive archive; private Class FrameworkPropertiesClazz ; public static String KERNAL_BUNDLE_NAME = "com.taobao.maindex"; public static KernalBundle kernalBundle = null; public static boolean checkloadKernalBundle(Application application,String containerVersion,String currentProcessName) { File storageDir = new File(KernalConstants.baseContext.getFilesDir(),"storage"); final File kernalDir = new File(storageDir, KERNAL_BUNDLE_NAME); if (kernalDir.exists()) { try { kernalBundle = new KernalBundle(kernalDir,currentProcessName,containerVersion); kernalBundle.patchKernalDex(); kernalBundle.replacePathClassLoaderIfNeed(application); kernalBundle.patchKernalResource(application); return true; } catch (Exception e) { e.printStackTrace(); kernalBundle = null; deleteDirectory(kernalDir); return false; } } return false; } public static boolean hasKernalPatch(){ return KernalVersionManager.instance().isChanged("com.taobao.maindex"); } public static void clear(){ File storageDir = new File(KernalConstants.baseContext.getFilesDir(),"storage"); final File kernalDir = new File(storageDir, KERNAL_BUNDLE_NAME); if(kernalDir.exists()){ deleteDirectory(kernalDir); } } public static boolean downgradeRevision(File bundleDir,boolean forceDelete) throws IOException { return KernalBundleArchive.downgradeRevision(bundleDir,forceDelete); } public KernalBundle(final File bundleDir, final File file,String containerVersion,long dexPatchVersion) throws Exception { this.bundleDir = bundleDir; try { archive = new KernalBundleArchive(bundleDir, file,containerVersion,dexPatchVersion); } catch (IOException e) { e.printStackTrace(); if (bundleDir.exists()) { deleteDirectory(bundleDir); } throw new IOException("install kernal Bundlele fail ", e); } } public KernalBundle(final File bundleDir,String process,String installedVersion) throws Exception { KernalFileLock.getInstance().LockExclusive(bundleDir); this.bundleDir = bundleDir; File metaFile = new File(bundleDir, "meta"); String metaRevision = ""; try { if(KernalVersionManager.instance().DEXPATCH_VERSION>0 && KernalVersionManager.instance().isDexPatched("com.taobao.maindex")){ archive = new KernalBundleArchive(KernalConstants.baseContext,bundleDir,"",process,installedVersion,KernalVersionManager.instance().DEXPATCH_VERSION); }else { if (shouldSyncUpdateInThisProcess(process)) { archive = new KernalBundleArchive(KernalConstants.baseContext,bundleDir, "",process, installedVersion,-1); File revisionDir = archive.getRevisionDir(); if (!metaFile.exists()) { int retry = 3; do { metaFile.createNewFile(); if (metaFile.exists()) { break; } else { retry--; } } while (!metaFile.exists() && retry > 3); } else { DataInputStream in = new DataInputStream(new FileInputStream(metaFile)); metaRevision = in.readUTF(); quietClose(in); } if (!metaRevision.equals(revisionDir.getAbsolutePath())) { FileOutputStream fos = new FileOutputStream(metaFile); DataOutputStream out = new DataOutputStream(fos); out.writeUTF(revisionDir.getAbsolutePath()); out.flush(); fos.getFD().sync(); //this may be time-consuming quietClose(out); } } else { if (metaFile.exists()) { DataInputStream in = new DataInputStream(new FileInputStream(metaFile)); metaRevision = in.readUTF(); quietClose(in); if (metaRevision != null && new File(metaRevision).exists()) { archive = new KernalBundleArchive(KernalConstants.baseContext,bundleDir, metaRevision, process,installedVersion,-1); } else { throw new IOException("can not find valid revision"); } } else { throw new IOException("can not find kernal meta"); } } } } catch (IOException e) { e.printStackTrace(); throw new IOException("resolve kernal Bundlele fail ", e); }finally { KernalFileLock.getInstance().unLock(bundleDir); } } public void patchKernalDex() throws Exception { DexFile[] dexFile = archive.getOdexFile(); if ((dexFile != null&&dexFile.length>0) || archive.getLibraryDirectory().exists()) { installKernalBundle(KernalConstants.baseContext.getClassLoader(),archive); FrameworkPropertiesClazz = archive.getOdexFile()[dexFile.length-1].loadClass("android.taobao.atlas.framework.FrameworkProperties",ClassLoader.getSystemClassLoader()); if(FrameworkPropertiesClazz==null && isDeubgMode()){ Log.e("KernalBundle","main dex is not match, library awo test?"); return; } Field versionField = FrameworkPropertiesClazz.getDeclaredField("version"); versionField.setAccessible(true); String version = (String)versionField.get(FrameworkPropertiesClazz.newInstance()); if(!KernalVersionManager.instance().CURRENT_VERSIONAME.equals(version)){ if(isDeubgMode()){ Log.e("KernalBundle","main dex is not match, awo test?"); }else { throw new RuntimeException("maindex version is not mismatch"); } } } } public void replacePathClassLoaderIfNeed(Application application){ ClassLoader originalClassLoader = null; if(Build.VERSION.SDK_INT>=24) { originalClassLoader = application.getClassLoader(); ClassLoader loader = getClass().getClassLoader(); boolean needReplace = false; do{ if(loader.getClass().getName().equals(PathClassLoader.class.getName())){ needReplace = true; break; } } while((loader=loader.getParent())!=null); if(needReplace){ try { NClassLoader.replacePathClassLoader(KernalConstants.baseContext,KernalBundle.class.getClassLoader()); } catch (Exception e) { throw new RuntimeException(e); } } } try { Class RuntimeVariablesClass = application.getClassLoader().loadClass("android.taobao.atlas.runtime.RuntimeVariables"); if(originalClassLoader!=null) { RuntimeVariablesClass.getDeclaredField("sRawClassLoader").set(RuntimeVariablesClass, originalClassLoader); } if(FrameworkPropertiesClazz!=null){ RuntimeVariablesClass.getDeclaredField("FrameworkPropertiesClazz").set(RuntimeVariablesClass, FrameworkPropertiesClazz); }else if(!isDeubgMode()){ throw new RuntimeException("FrameworkPropertiesClazz find error,will be rollback!"); } RuntimeVariablesClass.getDeclaredField("androidApplication").set(RuntimeVariablesClass,application); RuntimeVariablesClass.getDeclaredField("delegateResources").set(RuntimeVariablesClass,KernalConstants.baseContext.getResources()); } catch (Throwable e) { e.printStackTrace(); } } public void patchKernalResource(Application application) throws Exception{ if(archive.hasResources()){ Class DelegateResourcesClazz = application.getClassLoader().loadClass("android.taobao.atlas.runtime.DelegateResources"); DelegateResourcesClazz.getDeclaredMethod("addApkpatchResources", String.class) .invoke(DelegateResourcesClazz, archive.getArchiveFile().getAbsolutePath()); } } public int getState() { return 0; } public void update(File file,String version,long dexPatchVersion) throws IOException { try { archive.newRevision(file,version,dexPatchVersion); } catch (Exception e) { throw new IOException("Could not update bundle " + toString(), e); } } private static boolean isDebug(Context context){ try { final ApplicationInfo app_info = context.getApplicationInfo(); boolean debug = (app_info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; return debug; }catch (Throwable throwable){ return false; } } /** * 安装so库 */ private static void extract(String zipPath,String entryPath,File targetPath){ ZipFile zip = null; try { zip = new ZipFile(new File(zipPath)); ZipEntry entry = zip.getEntry(entryPath); BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(targetPath)); BufferedInputStream bi = new BufferedInputStream(zip.getInputStream(entry)); byte[] readContent = new byte[600]; int readCount = bi.read(readContent); while (readCount != -1) { bos.write(readContent, 0,readCount); readCount =bi.read(readContent); } bos.close(); }catch(final Exception e){ e.printStackTrace(); }finally{ try{ if(zip!=null){ zip.close(); } }catch(Throwable e){} } } /** * Locates a given field anywhere in the class inheritance hierarchy. * * @param instance an object to search the field into. * @param name field name * @return a field object * @throws NoSuchFieldException if the field cannot be located */ private static Field findField(Object instance, String name) throws NoSuchFieldException { for (Class<?> clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass()) { try { Field field = clazz.getDeclaredField(name); if (!field.isAccessible()) { field.setAccessible(true); } return field; } catch (NoSuchFieldException e) { // ignore and search next } } throw new NoSuchFieldException("Field " + name + " not found in " + instance.getClass()); } /** * Replace the value of a field containing a non null array, by a new array containing the * elements of the original array plus the elements of extraElements. * * @param instance the instance whose field is to be modified. * @param fieldName the field to modify. * @param extraElement element to append at the end of the array. */ private static void expandFieldArray(Object instance, String fieldName, Object[] extraElement) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field jlrField = findField(instance, fieldName); Object[] original = (Object[]) jlrField.get(instance); Object[] combined = (Object[]) Array.newInstance( original.getClass().getComponentType(), original.length + extraElement.length); for (int i = 0; i<extraElement.length; i++) { combined[i] = extraElement[i]; } System.arraycopy(original, 0, combined, extraElement.length, original.length); jlrField.set(instance, combined); } private static void expandFieldList(Object instance, String fieldName, Object extraElement) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field jlrField = findField(instance, fieldName); List original = (List) jlrField.get(instance); original.add(0,extraElement); } private static boolean replaceElement(Object instance,String fieldName,Object replaceElement) throws NoSuchFieldException,IllegalArgumentException, IllegalAccessException{ boolean replaceSuccess = false; Field jlrField = findField(instance, fieldName); Object[] original = (Object[]) jlrField.get(instance); for(int x=0; x<original.length; x++){ Object element = original[x]; File apkFile = findDexRawFile(element); if(apkFile!=null){ if(apkFile.getAbsolutePath()!=null && apkFile.getAbsolutePath().contains(KernalConstants.baseContext.getPackageName())){ original[x] = replaceElement; replaceSuccess = true; break; } } } return replaceSuccess; } private static File findDexRawFile(Object element){ Field field = null; File dexRawFile = null; if(Build.VERSION.SDK_INT>=25) { try { field = element.getClass().getDeclaredField("path"); field.setAccessible(true); dexRawFile = (File)field.get(element); return dexRawFile; }catch(Throwable e){} } try { field = element.getClass().getDeclaredField("file"); field.setAccessible(true); dexRawFile = (File)field.get(element); }catch(Throwable e){} if(field==null){ try { field = element.getClass().getDeclaredField("zip"); field.setAccessible(true); dexRawFile = (File)field.get(element); }catch(Throwable e){} } return dexRawFile; } public static boolean installKernalBundle(ClassLoader updateClassLoader, KernalBundleArchive archive) throws IOException, NoSuchFieldException, IllegalAccessException { Object[] element = null; boolean success = false; try { ClassLoader loader = updateClassLoader; Field pathListField = findField(loader, "pathList"); Object dexPathList = pathListField.get(loader); if (archive.getOdexFile() != null) { element = makeDexElement(archive.getArchiveFile(), archive.getOdexFile()); if (element == null||element.length == 0) { throw new IOException("makeDexElement failed"); } //增加kernal bundle if (Build.VERSION.SDK_INT > 20) { success = replaceElement(dexPathList, "dexElements", element[0]); if(!success){ throw new IOException("replaceElement failed"); } } else { expandFieldArray(dexPathList, "dexElements", element); } } //增加kernal bundle library File libraryDirectory = archive.getLibraryDirectory(); if (!TextUtils.isEmpty(libraryDirectory.getAbsolutePath()) && libraryDirectory.exists()) { if(Build.VERSION.SDK_INT<23){ expandFieldArray(dexPathList, "nativeLibraryDirectories", new Object[]{libraryDirectory}); }else{ expandFieldList(dexPathList, "nativeLibraryDirectories", libraryDirectory); } if(Build.VERSION.SDK_INT>=23){ Object nativeLibraryElement = makeNativeLibraryElement(libraryDirectory); expandFieldArray(dexPathList, "nativeLibraryPathElements", new Object[]{nativeLibraryElement}); } } return true; } catch (Exception e) { throw new IOException("install kernal fail", e); } } private void quietClose(Closeable closeable){ try{ if(closeable!=null){ closeable.close(); } }catch (Throwable e){ } } static Class[] constructorArgs3 = {File.class, ZipFile.class, DexFile.class}; static Class[] constructorArgs2 = {File.class, File.class, DexFile.class}; static Class[] constructorArgs1 = {File.class, boolean.class, File.class, DexFile.class}; public static Object[] makeDexElement(File file,DexFile[] dex) throws Exception{ Object []objects = new Object[dex.length]; for (int i = 0; i < dex.length; i ++) { try { Class Element = Class.forName("dalvik.system.DexPathList$Element"); Constructor cons = getElementConstructor(Element, constructorArgs1); if (cons != null) { objects[i] = cons.newInstance(null, false, new File(KernalConstants.baseContext.getApplicationInfo().sourceDir), dex[i]); } else { cons = getElementConstructor(Element, constructorArgs2); if (cons != null) { objects[i] = cons.newInstance(null, null, dex[i]); } else { cons = getElementConstructor(Element, constructorArgs3); if (cons != null) { objects[i] = cons.newInstance(null, null, dex[i]); } } } } catch (Exception e) { throw new RuntimeException("make DexElement fail", e); } } return objects; } // for api level >=23 public static Object makeNativeLibraryElement(File dir) throws IOException{ try{ Class Element = Class.forName("dalvik.system.DexPathList$Element"); Constructor cons = getElementConstructor(Element,constructorArgs1); if(cons!=null){ return cons.newInstance(dir,true, null,null); }else{ throw new IOException("make nativeElement fail | error constructor"); } }catch(Exception e){ throw new IOException("make nativeElement fail",e); } } private static Constructor getElementConstructor(Class element,Class... args){ try{ return element.getDeclaredConstructor(args); }catch(Throwable e){ Log.w("KernalBundleImpl","can not create element by args" + args); } return null; } public KernalBundleArchive getArchive() { return archive; } public File getRevisionDir(){ return getArchive().getRevisionDir(); } public File getRevisionZip(){ return getArchive().getArchiveFile(); } public static boolean shouldSyncUpdateInThisProcess(String process){ String processName = process; if(processName!=null && (processName.equals(KernalConstants.baseContext.getPackageName()) || processName.toLowerCase().contains(":safemode") )){ return true; }else{ return false; } } public static void deleteDirectory(final File path) { final File[] files = path.listFiles(); if (files == null){ return; } for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { deleteDirectory(files[i]); } else { files[i].delete(); } } path.delete(); } public boolean isDeubgMode() { try { /** * enable patch debug if in debug mode */ final ApplicationInfo app_info = KernalConstants.baseContext.getApplicationInfo(); boolean DEBUG = (app_info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; if (DEBUG) { return true; } SharedPreferences sharedPreferences = KernalConstants.baseContext.getSharedPreferences("dynamic_test",Context.MODE_PRIVATE); boolean dynamic_test_flag = sharedPreferences.getBoolean("dynamic_test_key",false); if(dynamic_test_flag){ return true; } } catch (final Exception e) { return false; } return false; } // public static void installExternalDexs(Context context){ // String externalDexDir = context.getFilesDir()+File.separator+"external_dexs"; // File dexDir = new File(externalDexDir); // if(dexDir.exists()) { // File[] dexFiles = dexDir.listFiles(new FilenameFilter() { // @Override // public boolean accept(File dir, String filename) { // if (filename.endsWith(".dex")) { // return true; // } else { // return false; // } // } // }); // if(dexFiles!=null && dexFiles.length>0){ // File odex ; // Object[] element = null; // DexFile[]dexFiles1 = new DexFile[dexFiles.length]; // for(int x=0;x<dexFiles.length;x++){ // odex = new File(dexFiles[x].getAbsolutePath()+".odex"); // try { // DexFile dexFile = DexFile.loadDex(dexFiles[x].getAbsolutePath(), odex.getAbsolutePath(), 0); // dexFiles1[x] = dexFile; // } catch (Throwable e) { // e.printStackTrace(); // } // try { // element = makeDexElement(null, dexFiles1); // if (element != null && element.length > 0) { // ClassLoader loader = KernalBundle.class.getClassLoader(); // Field pathListField = findField(loader, "pathList"); // Object dexPathList = pathListField.get(loader); // expandFieldArray(dexPathList, "dexElements", element); // } // } catch (IOException e) { // e.printStackTrace(); // } catch (IllegalAccessException e) { // e.printStackTrace(); // } catch (NoSuchFieldException e) { // e.printStackTrace(); // } // // } // } // } // } }