| 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 | |
| 120 // data directory first. | |
| 121 // https://code.google.com/p/android/issues/detail?id=79480 | |
| 122 if (mIsPrimaryProcess) { | 111 if (mIsPrimaryProcess) { |
| 112 // Primary process: Copies native libraries into the app's data dire
ctory. |
| 123 ensureAppFilesSubDirExists(); | 113 ensureAppFilesSubDirExists(); |
| 124 LockFile lockFile = LockFile.acquireRuntimeLock(copyLibsLockFile); | 114 LockFile lockFile = LockFile.acquireRuntimeLock(copyLibsLockFile); |
| 125 if (lockFile == null) { | 115 if (lockFile == null) { |
| 126 LockFile.waitForRuntimeLock(copyLibsLockFile, 10 * 1000); | 116 LockFile.waitForRuntimeLock(copyLibsLockFile, 10 * 1000); |
| 127 } else { | 117 } else { |
| 128 try { | 118 try { |
| 129 localLibsDir.mkdir(); | 119 localLibsDir.mkdir(); |
| 130 localLibsDir.setReadable(true, false); | 120 localLibsDir.setReadable(true, false); |
| 131 localLibsDir.setExecutable(true, false); | 121 localLibsDir.setExecutable(true, false); |
| 132 copyChangedFiles(libDir, localLibsDir); | 122 copyChangedFiles(libDir, localLibsDir); |
| 133 } finally { | 123 } finally { |
| 134 lockFile.release(); | 124 lockFile.release(); |
| 135 } | 125 } |
| 136 } | 126 } |
| 137 } else { | 127 } else { |
| 138 // TODO: Work around this issue by using APK splits to install each
dex / lib. | 128 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
| 139 throw new RuntimeException("Incremental install does not work on And
roid M+ " | 129 // TODO: Work around this issue by using APK splits to install e
ach dex / lib. |
| 140 + "with isolated processes. Use the gn arg:\n" | 130 throw new RuntimeException("Incremental install does not work on
Android M+ " |
| 141 + " disable_incremental_isolated_processes=true\n" | 131 + "with isolated processes. Use the gn arg:\n" |
| 142 + "and try again."); | 132 + " disable_incremental_isolated_processes=true\n" |
| 133 + "and try again."); |
| 134 } |
| 135 // Other processes: Waits for primary process to finish copying. |
| 136 LockFile.waitForRuntimeLock(copyLibsLockFile, 10 * 1000); |
| 143 } | 137 } |
| 144 return localLibsDir; | 138 addNativeLibrarySearchPath(localLibsDir); |
| 145 } | 139 } |
| 146 | 140 |
| 147 @SuppressWarnings("unchecked") | 141 @SuppressWarnings("unchecked") |
| 148 private void addNativeLibrarySearchPath(File nativeLibDir) throws Reflective
OperationException { | 142 private void addNativeLibrarySearchPath(File nativeLibDir) throws Reflective
OperationException { |
| 149 Object dexPathList = Reflect.getField(mClassLoader, "pathList"); | 143 Object dexPathList = Reflect.getField(mClassLoader, "pathList"); |
| 150 Object currentDirs = Reflect.getField(dexPathList, "nativeLibraryDirecto
ries"); | 144 Object currentDirs = Reflect.getField(dexPathList, "nativeLibraryDirecto
ries"); |
| 151 File[] newDirs = new File[] { nativeLibDir }; | 145 File[] newDirs = new File[] { nativeLibDir }; |
| 152 // Switched from an array to an ArrayList in Lollipop. | 146 // Switched from an array to an ArrayList in Lollipop. |
| 153 if (currentDirs instanceof List) { | 147 if (currentDirs instanceof List) { |
| 154 List<File> dirsAsList = (List<File>) currentDirs; | 148 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) { | 181 if (!dest.exists() || dest.lastModified() != lastModified) { |
| 188 Log.i(TAG, "Copying " + src + " -> " + dest); | 182 Log.i(TAG, "Copying " + src + " -> " + dest); |
| 189 FileInputStream istream = new FileInputStream(src); | 183 FileInputStream istream = new FileInputStream(src); |
| 190 FileOutputStream ostream = new FileOutputStream(dest); | 184 FileOutputStream ostream = new FileOutputStream(dest); |
| 191 ostream.getChannel().transferFrom(istream.getChannel(), 0, istream.g
etChannel().size()); | 185 ostream.getChannel().transferFrom(istream.getChannel(), 0, istream.g
etChannel().size()); |
| 192 istream.close(); | 186 istream.close(); |
| 193 ostream.close(); | 187 ostream.close(); |
| 194 dest.setReadable(true, false); | 188 dest.setReadable(true, false); |
| 195 dest.setExecutable(true, false); | 189 dest.setExecutable(true, false); |
| 196 dest.setLastModified(lastModified); | 190 dest.setLastModified(lastModified); |
| 191 } else { |
| 192 Log.i(TAG, "Up-to-date: " + dest); |
| 197 } | 193 } |
| 198 } | 194 } |
| 199 | 195 |
| 200 private void ensureAppFilesSubDirExists() { | 196 private void ensureAppFilesSubDirExists() { |
| 201 mAppFilesSubDir.mkdir(); | 197 mAppFilesSubDir.mkdir(); |
| 202 mAppFilesSubDir.setExecutable(true, false); | 198 mAppFilesSubDir.setExecutable(true, false); |
| 203 } | 199 } |
| 204 | 200 |
| 205 private void createSymlink(String to, File from) throws ReflectiveOperationE
xception { | 201 private void createSymlink(String to, File from) throws ReflectiveOperationE
xception { |
| 206 Reflect.invokeMethod(mLibcoreOs, "symlink", to, from.getAbsolutePath()); | 202 Reflect.invokeMethod(mLibcoreOs, "symlink", to, from.getAbsolutePath()); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 223 Object[] entries = new Object[files.length]; | 219 Object[] entries = new Object[files.length]; |
| 224 File emptyDir = new File(""); | 220 File emptyDir = new File(""); |
| 225 for (int i = 0; i < files.length; ++i) { | 221 for (int i = 0; i < files.length; ++i) { |
| 226 File file = files[i]; | 222 File file = files[i]; |
| 227 Object dexFile = Reflect.invokeMethod(clazz, "loadDexFile", file, op
timizedDirectory); | 223 Object dexFile = Reflect.invokeMethod(clazz, "loadDexFile", file, op
timizedDirectory); |
| 228 entries[i] = Reflect.newInstance(entryClazz, emptyDir, false, file,
dexFile); | 224 entries[i] = Reflect.newInstance(entryClazz, emptyDir, false, file,
dexFile); |
| 229 } | 225 } |
| 230 return entries; | 226 return entries; |
| 231 } | 227 } |
| 232 } | 228 } |
| OLD | NEW |