| OLD | NEW |
| 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.incrementalinstall; | 5 package org.chromium.incrementalinstall; |
| 6 | 6 |
| 7 import android.content.Context; | 7 import android.content.Context; |
| 8 import android.os.Build; | 8 import android.os.Build; |
| 9 import android.util.Log; | 9 import android.util.Log; |
| 10 | 10 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 Object[] additionalElements = makeDexElements(dexFilesArr, optimizedDir)
; | 96 Object[] additionalElements = makeDexElements(dexFilesArr, optimizedDir)
; |
| 97 Reflect.setField( | 97 Reflect.setField( |
| 98 dexPathList, "dexElements", Reflect.concatArrays(dexElements, ad
ditionalElements)); | 98 dexPathList, "dexElements", Reflect.concatArrays(dexElements, ad
ditionalElements)); |
| 99 } | 99 } |
| 100 | 100 |
| 101 /** | 101 /** |
| 102 * Sets up all libraries within |libDir| to be loadable by System.loadLibrar
y(). | 102 * Sets up all libraries within |libDir| to be loadable by System.loadLibrar
y(). |
| 103 */ | 103 */ |
| 104 void importNativeLibs(File libDir) throws ReflectiveOperationException, IOEx
ception { | 104 void importNativeLibs(File libDir) throws ReflectiveOperationException, IOEx
ception { |
| 105 Log.i(TAG, "Importing native libraries from: " + libDir); | 105 Log.i(TAG, "Importing native libraries from: " + libDir); |
| 106 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | 106 // The library copying is not necessary on older devices, but we do it a
nyways to |
| 107 libDir = prepareNativeLibsAndroidM(libDir); | 107 // simplify things (it's fast compared to dexing). |
| 108 } | 108 // https://code.google.com/p/android/issues/detail?id=79480 |
| 109 addNativeLibrarySearchPath(libDir); | |
| 110 } | |
| 111 | |
| 112 /** | |
| 113 * Primary process: Copies native libraries into the app's data directory | |
| 114 * Other processes: Waits for primary process to finish copying. | |
| 115 */ | |
| 116 private File prepareNativeLibsAndroidM(File libDir) throws IOException { | |
| 117 File localLibsDir = new File(mAppFilesSubDir, "lib"); | 109 File localLibsDir = new File(mAppFilesSubDir, "lib"); |
| 118 File copyLibsLockFile = new File(mAppFilesSubDir, "libcopy.lock"); | 110 File copyLibsLockFile = new File(mAppFilesSubDir, "libcopy.lock"); |
| 119 // Due to a new SELinux policy, all libs must be copied into the app's | 111 // Due to a new SELinux policy, all libs must be copied into the app's |
| 120 // data directory first. | 112 // data directory first. |
| 121 // https://code.google.com/p/android/issues/detail?id=79480 | 113 // https://code.google.com/p/android/issues/detail?id=79480 |
| 122 if (mIsPrimaryProcess) { | 114 if (mIsPrimaryProcess) { |
| 123 LockFile lockFile = LockFile.acquireRuntimeLock(copyLibsLockFile); | 115 LockFile lockFile = LockFile.acquireRuntimeLock(copyLibsLockFile); |
| 124 if (lockFile == null) { | 116 if (lockFile == null) { |
| 125 LockFile.waitForRuntimeLock(copyLibsLockFile, 10 * 1000); | 117 LockFile.waitForRuntimeLock(copyLibsLockFile, 10 * 1000); |
| 126 } else { | 118 } else { |
| 127 try { | 119 try { |
| 128 ensureAppFilesSubDirExists(); | 120 ensureAppFilesSubDirExists(); |
| 129 localLibsDir.mkdir(); | 121 localLibsDir.mkdir(); |
| 130 localLibsDir.setReadable(true, false); | 122 localLibsDir.setReadable(true, false); |
| 131 localLibsDir.setExecutable(true, false); | 123 localLibsDir.setExecutable(true, false); |
| 132 copyChangedFiles(libDir, localLibsDir); | 124 copyChangedFiles(libDir, localLibsDir); |
| 133 } finally { | 125 } finally { |
| 134 lockFile.release(); | 126 lockFile.release(); |
| 135 } | 127 } |
| 136 } | 128 } |
| 137 } else { | 129 } else { |
| 138 // TODO: Work around this issue by using APK splits to install each
dex / lib. | 130 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
| 139 throw new RuntimeException("Incremental install does not work on And
roid M+ " | 131 // TODO: Work around this issue by using APK splits to install e
ach dex / lib. |
| 140 + "with isolated processes. Use the gn arg:\n" | 132 throw new RuntimeException("Incremental install does not work on
Android M+ " |
| 141 + " disable_incremental_isolated_processes=true\n" | 133 + "with isolated processes. Use the gn arg:\n" |
| 142 + "and try again."); | 134 + " disable_incremental_isolated_processes=true\n" |
| 135 + "and try again."); |
| 136 } |
| 137 // Other processes: Waits for primary process to finish copying. |
| 138 LockFile.waitForRuntimeLock(copyLibsLockFile, 10 * 1000); |
| 143 } | 139 } |
| 144 return localLibsDir; | 140 addNativeLibrarySearchPath(localLibsDir); |
| 145 } | 141 } |
| 146 | 142 |
| 147 @SuppressWarnings("unchecked") | 143 @SuppressWarnings("unchecked") |
| 148 private void addNativeLibrarySearchPath(File nativeLibDir) throws Reflective
OperationException { | 144 private void addNativeLibrarySearchPath(File nativeLibDir) throws Reflective
OperationException { |
| 149 Object dexPathList = Reflect.getField(mClassLoader, "pathList"); | 145 Object dexPathList = Reflect.getField(mClassLoader, "pathList"); |
| 150 Object currentDirs = Reflect.getField(dexPathList, "nativeLibraryDirecto
ries"); | 146 Object currentDirs = Reflect.getField(dexPathList, "nativeLibraryDirecto
ries"); |
| 151 File[] newDirs = new File[] { nativeLibDir }; | 147 File[] newDirs = new File[] { nativeLibDir }; |
| 152 // Switched from an array to an ArrayList in Lollipop. | 148 // Switched from an array to an ArrayList in Lollipop. |
| 153 if (currentDirs instanceof List) { | 149 if (currentDirs instanceof List) { |
| 154 List<File> dirsAsList = (List<File>) currentDirs; | 150 List<File> dirsAsList = (List<File>) currentDirs; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 if (!dest.exists() || dest.lastModified() != lastModified) { | 183 if (!dest.exists() || dest.lastModified() != lastModified) { |
| 188 Log.i(TAG, "Copying " + src + " -> " + dest); | 184 Log.i(TAG, "Copying " + src + " -> " + dest); |
| 189 FileInputStream istream = new FileInputStream(src); | 185 FileInputStream istream = new FileInputStream(src); |
| 190 FileOutputStream ostream = new FileOutputStream(dest); | 186 FileOutputStream ostream = new FileOutputStream(dest); |
| 191 ostream.getChannel().transferFrom(istream.getChannel(), 0, istream.g
etChannel().size()); | 187 ostream.getChannel().transferFrom(istream.getChannel(), 0, istream.g
etChannel().size()); |
| 192 istream.close(); | 188 istream.close(); |
| 193 ostream.close(); | 189 ostream.close(); |
| 194 dest.setReadable(true, false); | 190 dest.setReadable(true, false); |
| 195 dest.setExecutable(true, false); | 191 dest.setExecutable(true, false); |
| 196 dest.setLastModified(lastModified); | 192 dest.setLastModified(lastModified); |
| 193 } else { |
| 194 Log.i(TAG, "Up-to-date: " + dest); |
| 197 } | 195 } |
| 198 } | 196 } |
| 199 | 197 |
| 200 private void ensureAppFilesSubDirExists() { | 198 private void ensureAppFilesSubDirExists() { |
| 201 mAppFilesSubDir.mkdir(); | 199 mAppFilesSubDir.mkdir(); |
| 202 mAppFilesSubDir.setExecutable(true, false); | 200 mAppFilesSubDir.setExecutable(true, false); |
| 203 } | 201 } |
| 204 | 202 |
| 205 private void createSymlink(String to, File from) throws ReflectiveOperationE
xception { | 203 private void createSymlink(String to, File from) throws ReflectiveOperationE
xception { |
| 206 Reflect.invokeMethod(mLibcoreOs, "symlink", to, from.getAbsolutePath()); | 204 Reflect.invokeMethod(mLibcoreOs, "symlink", to, from.getAbsolutePath()); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 223 Object[] entries = new Object[files.length]; | 221 Object[] entries = new Object[files.length]; |
| 224 File emptyDir = new File(""); | 222 File emptyDir = new File(""); |
| 225 for (int i = 0; i < files.length; ++i) { | 223 for (int i = 0; i < files.length; ++i) { |
| 226 File file = files[i]; | 224 File file = files[i]; |
| 227 Object dexFile = Reflect.invokeMethod(clazz, "loadDexFile", file, op
timizedDirectory); | 225 Object dexFile = Reflect.invokeMethod(clazz, "loadDexFile", file, op
timizedDirectory); |
| 228 entries[i] = Reflect.newInstance(entryClazz, emptyDir, false, file,
dexFile); | 226 entries[i] = Reflect.newInstance(entryClazz, emptyDir, false, file,
dexFile); |
| 229 } | 227 } |
| 230 return entries; | 228 return entries; |
| 231 } | 229 } |
| 232 } | 230 } |
| OLD | NEW |