OSDN Git Service

Merge tag 'android-8.1.0_r33' into oreo-x86
[android-x86/frameworks-base.git] / core / jni / com_android_internal_content_NativeLibraryHelper.cpp
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #define LOG_TAG "NativeLibraryHelper"
18 //#define LOG_NDEBUG 0
19
20 #include "core_jni_helpers.h"
21
22 #include <nativehelper/ScopedUtfChars.h>
23 #include <androidfw/ZipFileRO.h>
24 #include <androidfw/ZipUtils.h>
25 #include <utils/Log.h>
26 #include <utils/Vector.h>
27
28 #include <zlib.h>
29
30 #include <fcntl.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <time.h>
34 #include <unistd.h>
35 #include <inttypes.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38
39 #include <memory>
40
41 #ifdef _PRC_COMPATIBILITY_PACKAGE_
42 #include "abipicker/ABIPicker.h"
43 #endif
44
45 #define APK_LIB "lib/"
46 #define APK_LIB_LEN (sizeof(APK_LIB) - 1)
47
48 #define LIB_PREFIX "/lib"
49 #define LIB_PREFIX_LEN (sizeof(LIB_PREFIX) - 1)
50
51 #define LIB_SUFFIX ".so"
52 #define LIB_SUFFIX_LEN (sizeof(LIB_SUFFIX) - 1)
53
54 #define RS_BITCODE_SUFFIX ".bc"
55
56 #define TMP_FILE_PATTERN "/tmp.XXXXXX"
57 #define TMP_FILE_PATTERN_LEN (sizeof(TMP_FILE_PATTERN) - 1)
58
59 #ifdef _PRC_COMPATIBILITY_PACKAGE_
60 #define X86ABI     "x86"
61 #define X8664ABI   "x86_64"
62 #endif
63
64 namespace android {
65
66 // These match PackageManager.java install codes
67 enum install_status_t {
68     INSTALL_SUCCEEDED = 1,
69     INSTALL_FAILED_INVALID_APK = -2,
70     INSTALL_FAILED_INSUFFICIENT_STORAGE = -4,
71     INSTALL_FAILED_CONTAINER_ERROR = -18,
72     INSTALL_FAILED_INTERNAL_ERROR = -110,
73     INSTALL_FAILED_NO_MATCHING_ABIS = -113,
74     NO_NATIVE_LIBRARIES = -114
75 };
76
77 typedef install_status_t (*iterFunc)(JNIEnv*, void*, ZipFileRO*, ZipEntryRO, const char*);
78
79 // Equivalent to android.os.FileUtils.isFilenameSafe
80 static bool
81 isFilenameSafe(const char* filename)
82 {
83     off_t offset = 0;
84     for (;;) {
85         switch (*(filename + offset)) {
86         case 0:
87             // Null.
88             // If we've reached the end, all the other characters are good.
89             return true;
90
91         case 'A' ... 'Z':
92         case 'a' ... 'z':
93         case '0' ... '9':
94         case '+':
95         case ',':
96         case '-':
97         case '.':
98         case '/':
99         case '=':
100         case '_':
101             offset++;
102             break;
103
104         default:
105             // We found something that is not good.
106             return false;
107         }
108     }
109     // Should not reach here.
110 }
111
112 static bool
113 isFileDifferent(const char* filePath, uint32_t fileSize, time_t modifiedTime,
114         uint32_t zipCrc, struct stat64* st)
115 {
116     if (lstat64(filePath, st) < 0) {
117         // File is not found or cannot be read.
118         ALOGV("Couldn't stat %s, copying: %s\n", filePath, strerror(errno));
119         return true;
120     }
121
122     if (!S_ISREG(st->st_mode)) {
123         return true;
124     }
125
126     if (static_cast<uint64_t>(st->st_size) != static_cast<uint64_t>(fileSize)) {
127         return true;
128     }
129
130     // For some reason, bionic doesn't define st_mtime as time_t
131     if (time_t(st->st_mtime) != modifiedTime) {
132         ALOGV("mod time doesn't match: %ld vs. %ld\n", st->st_mtime, modifiedTime);
133         return true;
134     }
135
136     int fd = TEMP_FAILURE_RETRY(open(filePath, O_RDONLY));
137     if (fd < 0) {
138         ALOGV("Couldn't open file %s: %s", filePath, strerror(errno));
139         return true;
140     }
141
142     // uLong comes from zlib.h. It's a bit of a wart that they're
143     // potentially using a 64-bit type for a 32-bit CRC.
144     uLong crc = crc32(0L, Z_NULL, 0);
145     unsigned char crcBuffer[16384];
146     ssize_t numBytes;
147     while ((numBytes = TEMP_FAILURE_RETRY(read(fd, crcBuffer, sizeof(crcBuffer)))) > 0) {
148         crc = crc32(crc, crcBuffer, numBytes);
149     }
150     close(fd);
151
152     ALOGV("%s: crc = %lx, zipCrc = %" PRIu32 "\n", filePath, crc, zipCrc);
153
154     if (crc != static_cast<uLong>(zipCrc)) {
155         return true;
156     }
157
158     return false;
159 }
160
161 static install_status_t
162 sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char*)
163 {
164     size_t* total = (size_t*) arg;
165     uint32_t uncompLen;
166
167     if (!zipFile->getEntryInfo(zipEntry, NULL, &uncompLen, NULL, NULL, NULL, NULL)) {
168         return INSTALL_FAILED_INVALID_APK;
169     }
170
171     *total += static_cast<size_t>(uncompLen);
172
173     return INSTALL_SUCCEEDED;
174 }
175
176 /*
177  * Copy the native library if needed.
178  *
179  * This function assumes the library and path names passed in are considered safe.
180  */
181 static install_status_t
182 copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName)
183 {
184     void** args = reinterpret_cast<void**>(arg);
185     jstring* javaNativeLibPath = (jstring*) args[0];
186     jboolean extractNativeLibs = *(jboolean*) args[1];
187     jboolean hasNativeBridge = *(jboolean*) args[2];
188
189     ScopedUtfChars nativeLibPath(env, *javaNativeLibPath);
190
191     uint32_t uncompLen;
192     uint32_t when;
193     uint32_t crc;
194
195     uint16_t method;
196     off64_t offset;
197
198     if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, NULL, &offset, &when, &crc)) {
199         ALOGD("Couldn't read zip entry info\n");
200         return INSTALL_FAILED_INVALID_APK;
201     }
202
203     if (!extractNativeLibs) {
204         // check if library is uncompressed and page-aligned
205         if (method != ZipFileRO::kCompressStored) {
206             ALOGD("Library '%s' is compressed - will not be able to open it directly from apk.\n",
207                 fileName);
208             return INSTALL_FAILED_INVALID_APK;
209         }
210
211         if (offset % PAGE_SIZE != 0) {
212             ALOGD("Library '%s' is not page-aligned - will not be able to open it directly from"
213                 " apk.\n", fileName);
214             return INSTALL_FAILED_INVALID_APK;
215         }
216
217         if (!hasNativeBridge) {
218           return INSTALL_SUCCEEDED;
219         }
220     }
221
222     // Build local file path
223     const size_t fileNameLen = strlen(fileName);
224     char localFileName[nativeLibPath.size() + fileNameLen + 2];
225
226     if (strlcpy(localFileName, nativeLibPath.c_str(), sizeof(localFileName)) != nativeLibPath.size()) {
227         ALOGD("Couldn't allocate local file name for library");
228         return INSTALL_FAILED_INTERNAL_ERROR;
229     }
230
231     *(localFileName + nativeLibPath.size()) = '/';
232
233     if (strlcpy(localFileName + nativeLibPath.size() + 1, fileName, sizeof(localFileName)
234                     - nativeLibPath.size() - 1) != fileNameLen) {
235         ALOGD("Couldn't allocate local file name for library");
236         return INSTALL_FAILED_INTERNAL_ERROR;
237     }
238
239     // Only copy out the native file if it's different.
240     struct tm t;
241     ZipUtils::zipTimeToTimespec(when, &t);
242     const time_t modTime = mktime(&t);
243     struct stat64 st;
244     if (!isFileDifferent(localFileName, uncompLen, modTime, crc, &st)) {
245         return INSTALL_SUCCEEDED;
246     }
247
248     char localTmpFileName[nativeLibPath.size() + TMP_FILE_PATTERN_LEN + 2];
249     if (strlcpy(localTmpFileName, nativeLibPath.c_str(), sizeof(localTmpFileName))
250             != nativeLibPath.size()) {
251         ALOGD("Couldn't allocate local file name for library");
252         return INSTALL_FAILED_INTERNAL_ERROR;
253     }
254
255     *(localTmpFileName + nativeLibPath.size()) = '/';
256
257     if (strlcpy(localTmpFileName + nativeLibPath.size(), TMP_FILE_PATTERN,
258                     TMP_FILE_PATTERN_LEN - nativeLibPath.size()) != TMP_FILE_PATTERN_LEN) {
259         ALOGI("Couldn't allocate temporary file name for library");
260         return INSTALL_FAILED_INTERNAL_ERROR;
261     }
262
263     int fd = mkstemp(localTmpFileName);
264     if (fd < 0) {
265         ALOGI("Couldn't open temporary file name: %s: %s\n", localTmpFileName, strerror(errno));
266         return INSTALL_FAILED_CONTAINER_ERROR;
267     }
268
269     if (!zipFile->uncompressEntry(zipEntry, fd)) {
270         ALOGI("Failed uncompressing %s to %s\n", fileName, localTmpFileName);
271         close(fd);
272         unlink(localTmpFileName);
273         return INSTALL_FAILED_CONTAINER_ERROR;
274     }
275
276     close(fd);
277
278     // Set the modification time for this file to the ZIP's mod time.
279     struct timeval times[2];
280     times[0].tv_sec = st.st_atime;
281     times[1].tv_sec = modTime;
282     times[0].tv_usec = times[1].tv_usec = 0;
283     if (utimes(localTmpFileName, times) < 0) {
284         ALOGI("Couldn't change modification time on %s: %s\n", localTmpFileName, strerror(errno));
285         unlink(localTmpFileName);
286         return INSTALL_FAILED_CONTAINER_ERROR;
287     }
288
289     // Set the mode to 755
290     static const mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |  S_IXGRP | S_IROTH | S_IXOTH;
291     if (chmod(localTmpFileName, mode) < 0) {
292         ALOGI("Couldn't change permissions on %s: %s\n", localTmpFileName, strerror(errno));
293         unlink(localTmpFileName);
294         return INSTALL_FAILED_CONTAINER_ERROR;
295     }
296
297     // Finally, rename it to the final name.
298     if (rename(localTmpFileName, localFileName) < 0) {
299         ALOGI("Couldn't rename %s to %s: %s\n", localTmpFileName, localFileName, strerror(errno));
300         unlink(localTmpFileName);
301         return INSTALL_FAILED_CONTAINER_ERROR;
302     }
303
304     ALOGV("Successfully moved %s to %s\n", localTmpFileName, localFileName);
305
306     return INSTALL_SUCCEEDED;
307 }
308
309 /*
310  * An iterator over all shared libraries in a zip file. An entry is
311  * considered to be a shared library if all of the conditions below are
312  * satisfied :
313  *
314  * - The entry is under the lib/ directory.
315  * - The entry name ends with ".so" and the entry name starts with "lib",
316  *   an exception is made for entries whose name is "gdbserver".
317  * - The entry filename is "safe" (as determined by isFilenameSafe).
318  *
319  */
320 class NativeLibrariesIterator {
321 private:
322     NativeLibrariesIterator(ZipFileRO* zipFile, bool debuggable, void* cookie)
323         : mZipFile(zipFile), mDebuggable(debuggable), mCookie(cookie), mLastSlash(NULL) {
324         fileName[0] = '\0';
325     }
326
327 public:
328     static NativeLibrariesIterator* create(ZipFileRO* zipFile, bool debuggable) {
329         void* cookie = NULL;
330         // Do not specify a suffix to find both .so files and gdbserver.
331         if (!zipFile->startIteration(&cookie, APK_LIB, NULL /* suffix */)) {
332             return NULL;
333         }
334
335         return new NativeLibrariesIterator(zipFile, debuggable, cookie);
336     }
337
338     ZipEntryRO next() {
339         ZipEntryRO next = NULL;
340         while ((next = mZipFile->nextEntry(mCookie)) != NULL) {
341             // Make sure this entry has a filename.
342             if (mZipFile->getEntryFileName(next, fileName, sizeof(fileName))) {
343                 continue;
344             }
345
346             // Make sure the filename is at least to the minimum library name size.
347             const size_t fileNameLen = strlen(fileName);
348             static const size_t minLength = APK_LIB_LEN + 2 + LIB_PREFIX_LEN + 1 + LIB_SUFFIX_LEN;
349             if (fileNameLen < minLength) {
350                 continue;
351             }
352
353             const char* lastSlash = strrchr(fileName, '/');
354             ALOG_ASSERT(lastSlash != NULL, "last slash was null somehow for %s\n", fileName);
355
356             // Skip directories.
357             if (*(lastSlash + 1) == 0) {
358                 continue;
359             }
360
361             // Make sure the filename is safe.
362             if (!isFilenameSafe(lastSlash + 1)) {
363                 continue;
364             }
365
366             if (!mDebuggable) {
367               // Make sure the filename starts with lib and ends with ".so".
368               if (strncmp(fileName + fileNameLen - LIB_SUFFIX_LEN, LIB_SUFFIX, LIB_SUFFIX_LEN)
369                   || strncmp(lastSlash, LIB_PREFIX, LIB_PREFIX_LEN)) {
370                   continue;
371               }
372             }
373
374             mLastSlash = lastSlash;
375             break;
376         }
377
378         return next;
379     }
380
381     inline const char* currentEntry() const {
382         return fileName;
383     }
384
385     inline const char* lastSlash() const {
386         return mLastSlash;
387     }
388
389     virtual ~NativeLibrariesIterator() {
390         mZipFile->endIteration(mCookie);
391     }
392 private:
393
394     char fileName[PATH_MAX];
395     ZipFileRO* const mZipFile;
396     const bool mDebuggable;
397     void* mCookie;
398     const char* mLastSlash;
399 };
400
401 static install_status_t
402 iterateOverNativeFiles(JNIEnv *env, jlong apkHandle, jstring javaCpuAbi,
403                        jboolean debuggable, iterFunc callFunc, void* callArg) {
404     ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
405     if (zipFile == NULL) {
406         return INSTALL_FAILED_INVALID_APK;
407     }
408
409     std::unique_ptr<NativeLibrariesIterator> it(
410             NativeLibrariesIterator::create(zipFile, debuggable));
411     if (it.get() == NULL) {
412         return INSTALL_FAILED_INVALID_APK;
413     }
414
415     const ScopedUtfChars cpuAbi(env, javaCpuAbi);
416     if (cpuAbi.c_str() == NULL) {
417         // This would've thrown, so this return code isn't observable by
418         // Java.
419         return INSTALL_FAILED_INVALID_APK;
420     }
421     ZipEntryRO entry = NULL;
422     while ((entry = it->next()) != NULL) {
423         const char* fileName = it->currentEntry();
424         const char* lastSlash = it->lastSlash();
425
426         // Check to make sure the CPU ABI of this file is one we support.
427         const char* cpuAbiOffset = fileName + APK_LIB_LEN;
428         const size_t cpuAbiRegionSize = lastSlash - cpuAbiOffset;
429
430         if (cpuAbi.size() == cpuAbiRegionSize && !strncmp(cpuAbiOffset, cpuAbi.c_str(), cpuAbiRegionSize)) {
431             install_status_t ret = callFunc(env, callArg, zipFile, entry, lastSlash + 1);
432
433             if (ret != INSTALL_SUCCEEDED) {
434                 ALOGV("Failure for entry %s", lastSlash + 1);
435                 return ret;
436             }
437         }
438     }
439
440     return INSTALL_SUCCEEDED;
441 }
442
443
444 static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supportedAbisArray,
445         jboolean debuggable) {
446     const int numAbis = env->GetArrayLength(supportedAbisArray);
447     Vector<ScopedUtfChars*> supportedAbis;
448
449     for (int i = 0; i < numAbis; ++i) {
450         supportedAbis.add(new ScopedUtfChars(env,
451             (jstring) env->GetObjectArrayElement(supportedAbisArray, i)));
452     }
453
454     ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
455     if (zipFile == NULL) {
456         return INSTALL_FAILED_INVALID_APK;
457     }
458
459     std::unique_ptr<NativeLibrariesIterator> it(
460             NativeLibrariesIterator::create(zipFile, debuggable));
461     if (it.get() == NULL) {
462         return INSTALL_FAILED_INVALID_APK;
463     }
464
465     ZipEntryRO entry = NULL;
466     int status = NO_NATIVE_LIBRARIES;
467     while ((entry = it->next()) != NULL) {
468         // We're currently in the lib/ directory of the APK, so it does have some native
469         // code. We should return INSTALL_FAILED_NO_MATCHING_ABIS if none of the
470         // libraries match.
471         if (status == NO_NATIVE_LIBRARIES) {
472             status = INSTALL_FAILED_NO_MATCHING_ABIS;
473         }
474
475         const char* fileName = it->currentEntry();
476         const char* lastSlash = it->lastSlash();
477
478         // Check to see if this CPU ABI matches what we are looking for.
479         const char* abiOffset = fileName + APK_LIB_LEN;
480         const size_t abiSize = lastSlash - abiOffset;
481         for (int i = 0; i < numAbis; i++) {
482             const ScopedUtfChars* abi = supportedAbis[i];
483             if (abi->size() == abiSize && !strncmp(abiOffset, abi->c_str(), abiSize)) {
484                 // The entry that comes in first (i.e. with a lower index) has the higher priority.
485                 if (((i < status) && (status >= 0)) || (status < 0) ) {
486                     status = i;
487                 }
488             }
489         }
490     }
491
492     for (int i = 0; i < numAbis; ++i) {
493         delete supportedAbis[i];
494     }
495
496     return status;
497 }
498
499 static jint
500 com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env, jclass clazz,
501         jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi,
502         jboolean extractNativeLibs, jboolean hasNativeBridge, jboolean debuggable)
503 {
504     void* args[] = { &javaNativeLibPath, &extractNativeLibs, &hasNativeBridge };
505     return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi, debuggable,
506             copyFileIfChanged, reinterpret_cast<void*>(args));
507 }
508
509 static jlong
510 com_android_internal_content_NativeLibraryHelper_sumNativeBinaries(JNIEnv *env, jclass clazz,
511         jlong apkHandle, jstring javaCpuAbi, jboolean debuggable)
512 {
513     size_t totalSize = 0;
514
515     iterateOverNativeFiles(env, apkHandle, javaCpuAbi, debuggable, sumFiles, &totalSize);
516
517     return totalSize;
518 }
519
520 static jint
521 com_android_internal_content_NativeLibraryHelper_findSupportedAbi_replace(
522         JNIEnv *env,
523         jclass clazz,
524         jlong apkHandle,
525         jobjectArray javaCpuAbisToSearch,
526         jboolean debuggable,
527         jstring apkPkgName,
528         jstring apkDir)
529 {
530 #ifdef _PRC_COMPATIBILITY_PACKAGE_
531
532     int abiType = findSupportedAbi(env, apkHandle, javaCpuAbisToSearch, debuggable);
533     if (apkDir == NULL) {
534         return (jint)abiType;
535     }
536
537     char abiFlag[256] = {'\0'};
538     ScopedUtfChars apkdir(env, apkDir);
539     size_t apkdir_size = apkdir.size();
540     const int numAbis = env->GetArrayLength(javaCpuAbisToSearch);
541     Vector<ScopedUtfChars*> supportedAbis;
542
543     assert(apkdir_size < 256 - 15);
544     if (strlcpy(abiFlag, apkdir.c_str(), 256) != apkdir.size()) {
545         return (jint)abiType;
546     }
547
548     int abiIndex = 0;
549     abiFlag[apkdir_size] = '/';
550     abiFlag[apkdir_size + 1] = '.';
551     for (abiIndex = 0; abiIndex < numAbis; abiIndex++) {
552         ScopedUtfChars* abiName = new ScopedUtfChars(env,
553                  (jstring)env->GetObjectArrayElement(javaCpuAbisToSearch, abiIndex));
554         supportedAbis.push_back(abiName);
555         if (abiName == NULL || abiName->c_str() == NULL || abiName->size() <= 0) {
556             break;
557         }
558         if ((strlcpy(abiFlag + apkdir_size + 2, abiName->c_str(), 256 - apkdir_size - 2)
559                     == abiName->size()) && (access(abiFlag, F_OK) == 0)) {
560             abiType = abiIndex;
561             break;
562         }
563     }
564
565     if (abiIndex < numAbis) {
566         for (int j = 0; j < abiIndex; ++j) {
567             if (supportedAbis[j] != NULL) {
568                 delete supportedAbis[j];
569             }
570         }
571         return (jint)abiType;
572     }
573
574     do {
575         if (abiType < 0 || abiType >= numAbis) {
576             break;
577         }
578
579         if (0 != strcmp(supportedAbis[abiType]->c_str(), X86ABI) &&
580                 0 != strcmp(supportedAbis[abiType]->c_str(), X8664ABI)) {
581             break;
582         }
583
584         ScopedUtfChars name(env, apkPkgName);
585         if (NULL == name.c_str()) {
586             break;
587         }
588
589         if (isInOEMWhiteList(name.c_str())) {
590             break;
591         }
592
593         ABIPicker picker(name.c_str(),supportedAbis);
594         if (!picker.buildNativeLibList((void*)apkHandle)) {
595             break;
596         }
597
598         abiType = picker.pickupRightABI(abiType);
599         if (abiType >= 0 && abiType < numAbis &&
600                 (strlcpy(abiFlag + apkdir_size + 2, supportedAbis[abiType]->c_str(),
601                          256 - apkdir_size - 2) == supportedAbis[abiType]->size())) {
602             int flagFp = creat(abiFlag, 0644);
603             if (flagFp != -1) {
604                 close(flagFp);
605             }
606         }
607
608     } while(0);
609
610     for (int i = 0; i < numAbis; ++i) {
611         delete supportedAbis[i];
612     }
613     return (jint)abiType;
614 #else
615     return (jint)findSupportedAbi(env, apkHandle, javaCpuAbisToSearch, debuggable);
616 #endif
617 }
618
619 enum bitcode_scan_result_t {
620   APK_SCAN_ERROR = -1,
621   NO_BITCODE_PRESENT = 0,
622   BITCODE_PRESENT = 1,
623 };
624
625 static jint
626 com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode(JNIEnv *env, jclass clazz,
627         jlong apkHandle) {
628     ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
629     void* cookie = NULL;
630     if (!zipFile->startIteration(&cookie, NULL /* prefix */, RS_BITCODE_SUFFIX)) {
631         return APK_SCAN_ERROR;
632     }
633
634     char fileName[PATH_MAX];
635     ZipEntryRO next = NULL;
636     while ((next = zipFile->nextEntry(cookie)) != NULL) {
637         if (zipFile->getEntryFileName(next, fileName, sizeof(fileName))) {
638             continue;
639         }
640         const char* lastSlash = strrchr(fileName, '/');
641         const char* baseName = (lastSlash == NULL) ? fileName : fileName + 1;
642         if (isFilenameSafe(baseName)) {
643             zipFile->endIteration(cookie);
644             return BITCODE_PRESENT;
645         }
646     }
647
648     zipFile->endIteration(cookie);
649     return NO_BITCODE_PRESENT;
650 }
651
652 static jlong
653 com_android_internal_content_NativeLibraryHelper_openApk(JNIEnv *env, jclass, jstring apkPath)
654 {
655     ScopedUtfChars filePath(env, apkPath);
656     ZipFileRO* zipFile = ZipFileRO::open(filePath.c_str());
657
658     return reinterpret_cast<jlong>(zipFile);
659 }
660
661 static void
662 com_android_internal_content_NativeLibraryHelper_close(JNIEnv *env, jclass, jlong apkHandle)
663 {
664     delete reinterpret_cast<ZipFileRO*>(apkHandle);
665 }
666
667 static const JNINativeMethod gMethods[] = {
668     {"nativeOpenApk",
669             "(Ljava/lang/String;)J",
670             (void *)com_android_internal_content_NativeLibraryHelper_openApk},
671     {"nativeClose",
672             "(J)V",
673             (void *)com_android_internal_content_NativeLibraryHelper_close},
674     {"nativeCopyNativeBinaries",
675             "(JLjava/lang/String;Ljava/lang/String;ZZZ)I",
676             (void *)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries},
677     {"nativeSumNativeBinaries",
678             "(JLjava/lang/String;Z)J",
679             (void *)com_android_internal_content_NativeLibraryHelper_sumNativeBinaries},
680     {"nativeFindSupportedAbiReplace",
681             "(J[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)I",
682             (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi_replace},
683     {"hasRenderscriptBitcode", "(J)I",
684             (void *)com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode},
685 };
686
687
688 int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env)
689 {
690     return RegisterMethodsOrDie(env,
691             "com/android/internal/content/NativeLibraryHelper", gMethods, NELEM(gMethods));
692 }
693
694 };