/* * * 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.framework.bundlestorage; import android.content.res.AssetManager; import android.os.Build; import android.os.Environment; import android.taobao.atlas.bundleInfo.AtlasBundleInfoManager; import android.taobao.atlas.bundleInfo.BundleListing; import android.taobao.atlas.framework.Framework; import android.taobao.atlas.util.*; import android.taobao.atlas.util.log.impl.AtlasMonitor; import android.taobao.atlas.versionInfo.BaselineInfoManager; import android.text.TextUtils; import android.taobao.atlas.hack.AtlasHacks; import android.taobao.atlas.runtime.RuntimeVariables; import android.util.Log; import dalvik.system.DexClassLoader; import dalvik.system.DexFile; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class BundleArchiveRevision { final static String BUNDLE_ODEX_FILE = "bundle.dex"; final static String BUNDLE_LEX_FILE = "bundle.lex"; final static String REFERENCE_PROTOCOL = "reference:"; final static String FILE_PROTOCOL = "file:"; final static String BUNDLE_FILE_NAME = "bundle.zip"; final static String INTERNAL_BUNDLE_FlAG = "internal"; final static String UPDATED_MARK="markUpdated"; /** * bundle updated by dynamic deploy */ Boolean mMarkUpdated; /** * the bundle revision file location. */ private final String revisionLocation; private final String containerVersion; private final long revisionNum; private final File revisionDir; private final String version; private final String location; private final File bundleFile; private ZipFile zipFile; private DexFile dexFile; private Manifest manifest; private boolean isDexOptDone = false; //There is no DexFile on yunos 2.x, so we use DexClassLoader; private ClassLoader dexClassLoader; BundleArchiveRevision(String location,long revisionNum, File revisionDir, InputStream inputStream,String v) throws IOException{ this.revisionNum = revisionNum; this.revisionDir = revisionDir; this.location = location; version = v; if (!this.revisionDir.exists()) { this.revisionDir.mkdirs(); } this.revisionLocation = FILE_PROTOCOL; this.bundleFile = new File(revisionDir, BUNDLE_FILE_NAME); ApkUtils.copyInputStreamToFile(inputStream, bundleFile); installSoLib(bundleFile); containerVersion = Framework.getContainerVersion(); updateMetadata(); if(Build.CPU_ABI.contains("x86")){ try { new File(revisionDir, INTERNAL_BUNDLE_FlAG).createNewFile(); }catch(Throwable e){ } } } /** * create bundle revision. if file is writable then move it to revisionDir, otherwise create meta file and reference * to it * * @param revisionNum * @param revisionDir * @param file * @throws IOException */ BundleArchiveRevision(String location,long revisionNum, File revisionDir, File file,String v) throws IOException{ this.revisionNum = revisionNum; this.revisionDir = revisionDir; this.location = location; version = v; boolean hasSO = false; Log.e("BundleArchiveRevision",revisionDir+""); if (AtlasBundleInfoManager.instance().getHasSO(location)){ hasSO = true; } if (!this.revisionDir.exists()) { this.revisionDir.mkdirs(); } // if (file.canWrite()) { // if (isSameDriver(revisionDir, file)) { // this.revisionLocation = FILE_PROTOCOL; // this.bundleFile = new File(revisionDir, BUNDLE_FILE_NAME); // file.renameTo(bundleFile); // } else { // this.revisionLocation = FILE_PROTOCOL; // this.bundleFile = new File(revisionDir, BUNDLE_FILE_NAME); // ApkUtils.copyInputStreamToFile(new FileInputStream(file), bundleFile); // } // installSoLib(bundleFile); // } else {// can not write // if ((AtlasHacks.LexFile != null && AtlasHacks.LexFile.getmClass() != null) || // (android.os.Build.HARDWARE.toLowerCase().contains("mt65") && file.getName().endsWith(".so"))){ // // 在阿里云2.x手机上使用的是LEX // this.revisionLocation = FILE_PROTOCOL; // this.bundleFile = new File(revisionDir, BUNDLE_FILE_NAME); // ApkUtils.copyInputStreamToFile(new FileInputStream(file), bundleFile); // installSoLib(bundleFile); // } else { // this.revisionLocation = REFERENCE_PROTOCOL + file.getAbsolutePath(); // this.bundleFile = file; // installSoLib(file); // } // } if(shouldCopyInstallFile(file)){ if (isSameDriver(revisionDir, file)) { this.revisionLocation = FILE_PROTOCOL; this.bundleFile = new File(revisionDir, BUNDLE_FILE_NAME); boolean result = file.renameTo(bundleFile); if(!result){ ApkUtils.copyInputStreamToFile(new FileInputStream(file), bundleFile); } } else { this.revisionLocation = FILE_PROTOCOL; this.bundleFile = new File(revisionDir, BUNDLE_FILE_NAME); ApkUtils.copyInputStreamToFile(new FileInputStream(file), bundleFile); } installSoLib(bundleFile); }else{ this.revisionLocation = REFERENCE_PROTOCOL + file.getAbsolutePath(); this.bundleFile = file; installSoLib(file); } containerVersion = Framework.getContainerVersion(); updateMetadata(); } BundleArchiveRevision(String location,long revisionNum, File revisionDir) throws IOException{ this.location = location; File metafile = new File(revisionDir, "meta"); if (metafile.exists()) { DataInputStream in = new DataInputStream(new FileInputStream(metafile)); this.revisionLocation = in.readUTF(); this.containerVersion = in.readUTF(); this.version = in.readUTF(); in.close(); if(!BaselineInfoManager.instance().isDexPatched(location)) { String wantedVersion = BaselineInfoManager.instance().getBaseBundleVersion(location); BundleListing.BundleInfo info = AtlasBundleInfoManager.instance().getBundleInfo(location); if (containerVersion == null || (!TextUtils.isEmpty(Framework.getContainerVersion()) && !containerVersion.equals(Framework.getContainerVersion())) || (!TextUtils.isEmpty(version) && !TextUtils.isEmpty(wantedVersion) && !version.equals(wantedVersion)) || (!TextUtils.isEmpty(info.getVersion()) && version!=null&&!version.equals("-1") && !version.equals(info.getVersion()) && !Framework.isDeubgMode())) { throw new BundleArchive.MisMatchException("mismatch bundle version" + revisionDir.getAbsolutePath()); } } } else { throw new IOException("Could not find meta file in " + revisionDir.getAbsolutePath()); } this.revisionNum = revisionNum; this.revisionDir = revisionDir; if (!this.revisionDir.exists()) { this.revisionDir.mkdirs(); } if (StringUtils.startWith(this.revisionLocation, REFERENCE_PROTOCOL)) { this.bundleFile = new File(StringUtils.substringAfter(this.revisionLocation, REFERENCE_PROTOCOL)); } else { this.bundleFile = new File(revisionDir, BUNDLE_FILE_NAME); } } private boolean shouldCopyInstallFile(File bundleFile) throws IOException{ if(bundleFile==null){ throw new IOException("bundle file not exists"); } File libDir = new File(RuntimeVariables.androidApplication.getFilesDir().getParentFile(), "lib"); if(!bundleFile.getAbsolutePath().startsWith(libDir.getAbsolutePath()) || (AtlasHacks.LexFile != null && AtlasHacks.LexFile.getmClass() != null) || (android.os.Build.HARDWARE.toLowerCase().contains("mt65") && bundleFile.getName().endsWith(".so")) ){ Log.e("BundleArchiveRevision","bundle patch: "+bundleFile.getAbsolutePath()); Log.e("BundleArchiveRevision","native lib path: "+RuntimeVariables.androidApplication.getApplicationInfo().nativeLibraryDir); return true; }else{ return false; } } /** * update the revision's metadata on the storage. */ void updateMetadata() throws IOException { File file = new File(revisionDir, "meta"); DataOutputStream out = null; try { if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } FileOutputStream fos = new FileOutputStream(file); out = new DataOutputStream(fos); out.writeUTF(revisionLocation); out.writeUTF(containerVersion); out.writeUTF(version); out.flush(); // fos.getFD().sync(); //this may be time-consuming } catch (IOException e) { String avliableSpace = ""; long filesSize = 0; long databasesSize = 0; long prefSize = 0; long rootSize = 0; try{ avliableSpace = FileUtils.getUsableSpace(Environment.getDataDirectory())+"M"; File rootDir = new File(String.format("/data/data/%s/"),RuntimeVariables.androidApplication.getPackageName()); rootSize = FileUtils.folderSize(rootDir); filesSize = FileUtils.folderSize(new File(rootDir, "files")); databasesSize = FileUtils.folderSize(new File(rootDir, "databases")); prefSize = FileUtils.folderSize(new File(rootDir, "shared_prefs")); }catch(Throwable e2){} throw new IOException("Could not save meta data " + file.getAbsolutePath()+" avliableSpace = " + avliableSpace + "rootSize = " + rootSize + " filesSize = " + filesSize + " databasesSize = " + databasesSize + " prefSize =" + prefSize, e); } finally { if (out != null) { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } } public long getRevisionNum() { return revisionNum; } public File getRevisionDir() { return revisionDir; } public File getRevisionFile() { return bundleFile; } public File findSoLibrary(String libraryName){ File file = new File(String.format("%s%s%s%s",revisionDir,File.separator,"lib",File.separator),libraryName); if(file.exists() && file.isFile() && file.length()>0){ return file; } // String abi = "armeabi"; // if(Build.CPU_ABI.contains("x86")){ // abi = "x86"; // } // String extractTag = String.format("%s%s/%s","lib/",abi,libraryName); if(bundleFile!=null){ ZipFile bundleZip = null; try{ bundleZip = new ZipFile(bundleFile); String extractTag = "lib/armeabi"; if(Build.CPU_ABI.contains("x86")){ if(bundleZip.getEntry("lib/x86/")!=null){ extractTag = "lib/x86"; } } extractTag = extractTag+"/"+libraryName; ZipEntry libEntry = null; if((libEntry = bundleZip.getEntry(extractTag))!=null){ extractEntry(bundleZip,libEntry); } /** * 二次检查 */ if(file.exists() && file.isFile()){ return file; } quiteClose(bundleZip); }catch(Throwable e){} finally { quiteClose(bundleZip); } } return null; } private void quiteClose(ZipFile zip){ try { if (zip != null) { zip.close(); } }catch(Throwable e){ } } public boolean isDexOpted() { if (isDexOptDone == false){ return false; } if (dexFile != null){ return true; } if (AtlasHacks.LexFile != null && AtlasHacks.LexFile.getmClass() != null) { File lexFile = new File(revisionDir, BUNDLE_LEX_FILE); return lexFile.exists() && lexFile.length() > 0; } File odexFile = new File(revisionDir, BUNDLE_ODEX_FILE); return odexFile.exists() && odexFile.length() > 0; } public synchronized void optDexFile() { if (isDexOpted()){ return; } if (AtlasHacks.LexFile != null && AtlasHacks.LexFile.getmClass() != null) { //yunos // TODO: need also cover logic of filelocks for YunOS. new DexClassLoader(bundleFile.getAbsolutePath(), revisionDir.getAbsolutePath(), null, ClassLoader.getSystemClassLoader()); isDexOptDone = true; return; } File odexFile = new File(revisionDir, BUNDLE_ODEX_FILE); long START = 0; START = System.currentTimeMillis(); try { if (AtlasFileLock.getInstance().LockExclusive(odexFile) == false) { Log.e("Framework","Failed to get file lock for " + bundleFile.getAbsolutePath()); } if (dexFile == null){ dexFile = com.taobao.android.runtime.RuntimeUtils.loadDex(RuntimeVariables.androidApplication, bundleFile.getAbsolutePath(), odexFile.getAbsolutePath(), 0); //dexFile = DexFile.loadDex(bundleFile.getAbsolutePath(), odexFile.getAbsolutePath(), 0); } //9月份版本明天发布先不集成 // isDexOptDone = checkDexValid(dexFile); isDexOptDone = true; } catch (IOException e) { // AtlasMonitor.getInstance().trace(AtlasMonitor.DEXOPT_FAIL, location, AtlasMonitor.DEXOPT_FAIL_MSG, // FileUtils.getDataAvailableSpace()); if (odexFile.exists()) { odexFile.delete(); } Log.e("Framework","Failed optDexFile '" + bundleFile.getAbsolutePath() + "' >>> ", e); AtlasMonitor.getInstance().trace(AtlasMonitor.CONTAINER_DEXOPT_FAIL, false, "0", e==null?"":e.getMessage(), bundleFile.getName()); } finally { AtlasFileLock.getInstance().unLock(odexFile); } Log.e("Framework","bundle archieve dexopt bundle " + bundleFile.getAbsolutePath() + " cost time = " + (System.currentTimeMillis() - START) + " ms"); return; } public boolean checkDexValid(DexFile dexFile) throws IOException { String applicationName = AtlasBundleInfoManager.instance().getBundleInfo(location).getApplicationName(); if(!TextUtils.isEmpty(applicationName)) { Class clazz = null; try { clazz = getClass().getClassLoader().loadClass(applicationName); }catch (ClassNotFoundException e){ } if(clazz == null) { try { dexFile.loadClass(applicationName,new ClassLoader(){}); // Enumeration<String> enumeration = dexFile.entries(); // while (enumeration.hasMoreElements()) { // if (enumeration.nextElement().replace("/", ".").equals(applicationName)) { // return true; // } // } return false; } catch (Throwable e) { return false; } } } return true; } @SuppressWarnings("serial") public static class DexLoadException extends RuntimeException{ DexLoadException(String e){ super(e); } } /** * 安装so库 * @throws IOException */ public void installSoLib(File bundle) throws IOException{ ZipFile zip = null; try { zip = new ZipFile(bundle); String extractTag = "lib/armeabi"; if(Build.CPU_ABI.contains("x86")){ if(zip.getEntry("lib/x86/")!=null){ extractTag = "lib/x86"; } } for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) { ZipEntry zipEntry = (ZipEntry)entries.nextElement(); String entryName = zipEntry.getName(); if (entryName.equalsIgnoreCase("../")){ continue; } if(entryName.indexOf(extractTag)!=-1) { extractEntry(zip,zipEntry); } } }catch(IOException e){ AtlasMonitor.getInstance().trace(AtlasMonitor.CONTAINER_SOLIB_UNZIP_FAIL, false, "0", e==null?"":e.getMessage(), bundle.getName()); throw e; }finally{ if(null!=zip){ zip.close(); } } } private void extractEntry(ZipFile zip ,ZipEntry zipEntry) throws IOException{ String entryName = zipEntry.getName(); String targetPath = String.format("%s%s%s%s%s",revisionDir,File.separator,"lib",File.separator, entryName.substring(entryName.lastIndexOf(File.separator)+1,entryName.length())); if (zipEntry.isDirectory()) { File decompressDirFile = new File(targetPath); if (!decompressDirFile.exists()) { decompressDirFile.mkdirs(); } }else{ String fileDir =targetPath.substring(0, targetPath.lastIndexOf("/")); File fileDirFile = new File(fileDir); if (!fileDirFile.exists()) { fileDirFile.mkdirs(); } BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(targetPath)); BufferedInputStream bi = new BufferedInputStream(zip.getInputStream(zipEntry)); byte[] readContent = new byte[1024]; int readCount = bi.read(readContent); while (readCount != -1) { bos.write(readContent, 0,readCount); readCount =bi.read(readContent); } bos.close(); bi.close(); } } public InputStream openAssetInputStream(String fileName) throws IOException { try { AssetManager assmgr = AssetManager.class.newInstance(); int cookie = (Integer) AtlasHacks.AssetManager_addAssetPath.invoke(assmgr, bundleFile.getAbsolutePath()); if (cookie != 0) { return assmgr.open(fileName); } } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { Log.e("Framework","Exception while openNonAssetInputStream >>>", e.getTargetException()); } return null; } public InputStream openNonAssetInputStream(String fileName) throws IOException { try { AssetManager assmgr = AssetManager.class.newInstance(); int cookie = (Integer) AtlasHacks.AssetManager_addAssetPath.invoke(assmgr, bundleFile.getAbsolutePath()); if (cookie != 0) { return assmgr.openNonAssetFd(cookie, fileName).createInputStream(); } } catch (Throwable e) { e.printStackTrace(); } return null; } public Manifest getManifest() throws IOException { if (manifest != null) { return manifest; } InputStream input = null; try { AssetManager assmgr = AssetManager.class.newInstance(); int cookie = (Integer) AtlasHacks.AssetManager_addAssetPath.invoke(assmgr, bundleFile.getAbsolutePath()); if (cookie != 0) { try { input = assmgr.open("OSGI.MF"); manifest = new Manifest(input); return manifest; } catch (FileNotFoundException e) { // log.warn("Could not find OSGI.MF in " + bundleFile.getAbsolutePath()); } catch (Exception e) { e.printStackTrace(); } } else { // AtlasMonitor.getInstance().trace(AtlasMonitor.BUNDLE_INSTALL_FAIL, location, AtlasMonitor.OSGI_ADD_PATH_FAILED_MSG, // FileUtils.getDataAvailableSpace()); } } catch (Exception e) { // AtlasMonitor.getInstance().trace(AtlasMonitor.BUNDLE_INSTALL_FAIL, location, AtlasMonitor.OSGI_ADD_PATH_FAILED_MSG, // FileUtils.getDataAvailableSpace()); } finally { if (input != null) { input.close(); } } return null; } Class<?> findClass(String className, ClassLoader cl) throws ClassNotFoundException { try { Class<?> clazz = null; if (AtlasHacks.LexFile != null && AtlasHacks.LexFile.getmClass() != null) { if (dexClassLoader == null) { File libDir = new File(RuntimeVariables.androidApplication.getFilesDir().getParentFile(),"lib"); dexClassLoader = new DexClassLoader(bundleFile.getAbsolutePath(), revisionDir.getAbsolutePath(), libDir.getAbsolutePath(), cl){ @Override public String findLibrary(String name){ String path = super.findLibrary(name); if(TextUtils.isEmpty(path)){ String fileName = System.mapLibraryName(name); File soFile = findSoLibrary(fileName); if(soFile!=null && soFile.exists()){ return soFile.getAbsolutePath(); } try { return (String) AtlasHacks.ClassLoader_findLibrary.invoke(Framework.getSystemClassLoader(), name); } catch (Exception e) { e.printStackTrace(); } return null; }else{ return path; } } }; } clazz = (Class<?>) AtlasHacks.DexClassLoader_findClass.invoke(dexClassLoader, className); return clazz; } if (isDexOpted() == false){ optDexFile(); } if (dexFile == null){ // loadDex(new File(revisionDir, BUNDLE_ODEX_FILE)); optDexFile(); } clazz = dexFile.loadClass(className, cl); return clazz; } catch (IllegalArgumentException e) { } catch (InvocationTargetException e) { } catch (Exception e) { if (e instanceof ClassNotFoundException) { //do nothing } else if (e instanceof DexLoadException){ throw (DexLoadException)e; } else { Log.e("Framework","Exception while find class in archive revision: " + bundleFile.getAbsolutePath(), e); } } return null; } /** * Returns an enumeration of URLs for the resource with the specified name. */ List<URL> getResources(String resName) throws IOException { final List<URL> results = new ArrayList<URL>(); ensureZipFile(); if (zipFile != null && zipFile.getEntry(resName) != null) { try { /* * File.toURL() is compliant with RFC 1738 in always creating absolute path names. If we construct the * URL by concatenating strings, we might end up with illegal URLs for relative names. */ @SuppressWarnings("deprecation") URL url = new URL("jar:" + bundleFile.toURL() + "!/" + resName); results.add(url); } catch (MalformedURLException ex) { throw new RuntimeException( ex); } } return results; } void close() throws Exception { if (zipFile != null) { zipFile.close(); } if (dexFile != null) { dexFile.close(); } } private boolean isSameDriver(File file1, File file2) { String mount1 = StringUtils.substringBetween(file1.getAbsolutePath(), "/", "/"); String mount2 = StringUtils.substringBetween(file2.getAbsolutePath(), "/", "/"); return StringUtils.equals(mount1, mount2); } private void ensureZipFile() throws IOException { if (this.zipFile == null) { this.zipFile = new ZipFile(bundleFile, ZipFile.OPEN_READ); } } public String getVersion(){ return TextUtils.isEmpty(version) ? "" : version; } /** * TODO 如何判断bundle是否更新过 * @return */ public boolean isUpdated(){ return getMarkUpdate(revisionDir); } private boolean getMarkUpdate(File bundleDir){ /** * 在一次运行中,更新标记状态保持不变; */ if(mMarkUpdated!=null){ return mMarkUpdated; } try{ File mUpdated = new File(bundleDir, UPDATED_MARK); if(mUpdated!=null&&mUpdated.exists()){ mMarkUpdated=true; }else{ mMarkUpdated=false; } }catch (Throwable e){ return false; } return mMarkUpdated; } }