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 |