NativeLibraryHelper.java revision cef0b39b9211882f59b6bfe1148e2cd247056693
1/*
2 * Copyright (C) 2010 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
17package com.android.internal.content;
18
19import android.content.pm.PackageManager;
20import android.util.Slog;
21
22import java.io.Closeable;
23import java.io.File;
24import java.io.IOException;
25
26/**
27 * Native libraries helper.
28 *
29 * @hide
30 */
31public class NativeLibraryHelper {
32    private static final String TAG = "NativeHelper";
33
34    private static final boolean DEBUG_NATIVE = false;
35
36    /**
37     * A handle to an opened APK. Used as input to the various NativeLibraryHelper
38     * methods. Allows us to scan and parse the APK exactly once instead of doing
39     * it multiple times.
40     *
41     * @hide
42     */
43    public static class ApkHandle implements Closeable {
44        final String apkPath;
45        final long apkHandle;
46
47        public static ApkHandle create(String path) throws IOException {
48            final long handle = nativeOpenApk(path);
49            if (handle == 0) {
50                throw new IOException("Unable to open APK: " + path);
51            }
52
53            return new ApkHandle(path, handle);
54        }
55
56        public static ApkHandle create(File path) throws IOException {
57            return create(path.getAbsolutePath());
58        }
59
60        private ApkHandle(String apkPath, long apkHandle) {
61            this.apkPath = apkPath;
62            this.apkHandle = apkHandle;
63        }
64
65        @Override
66        public void close() {
67            nativeClose(apkHandle);
68        }
69    }
70
71
72    private static native long nativeOpenApk(String path);
73    private static native void nativeClose(long handle);
74
75    private static native long nativeSumNativeBinaries(long handle, String cpuAbi);
76
77    /**
78     * Sums the size of native binaries in an APK for a given ABI.
79     *
80     * @return size of all native binary files in bytes
81     */
82    public static long sumNativeBinariesLI(ApkHandle handle, String abi) {
83        return nativeSumNativeBinaries(handle.apkHandle, abi);
84    }
85
86    private native static int nativeCopyNativeBinaries(long handle,
87            String sharedLibraryPath, String abiToCopy);
88
89    /**
90     * Copies native binaries to a shared library directory.
91     *
92     * @param handle APK file to scan for native libraries
93     * @param sharedLibraryDir directory for libraries to be copied to
94     * @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another
95     *         error code from that class if not
96     */
97    public static int copyNativeBinariesIfNeededLI(ApkHandle handle, File sharedLibraryDir,
98            String abi) {
99        return nativeCopyNativeBinaries(handle.apkHandle, sharedLibraryDir.getPath(), abi);
100    }
101
102    /**
103     * Checks if a given APK contains native code for any of the provided
104     * {@code supportedAbis}. Returns an index into {@code supportedAbis} if a matching
105     * ABI is found, {@link PackageManager#NO_NATIVE_LIBRARIES} if the
106     * APK doesn't contain any native code, and
107     * {@link PackageManager#INSTALL_FAILED_NO_MATCHING_ABIS} if none of the ABIs match.
108     */
109    public static int findSupportedAbi(ApkHandle handle, String[] supportedAbis) {
110        return nativeFindSupportedAbi(handle.apkHandle, supportedAbis);
111    }
112
113    private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis);
114
115    // Convenience method to call removeNativeBinariesFromDirLI(File)
116    public static boolean removeNativeBinariesLI(String nativeLibraryPath) {
117        return removeNativeBinariesFromDirLI(new File(nativeLibraryPath));
118    }
119
120    // Remove the native binaries of a given package. This simply
121    // gets rid of the files in the 'lib' sub-directory.
122    public static boolean removeNativeBinariesFromDirLI(File nativeLibraryDir) {
123        if (DEBUG_NATIVE) {
124            Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryDir.getPath());
125        }
126
127        boolean deletedFiles = false;
128
129        /*
130         * Just remove any file in the directory. Since the directory is owned
131         * by the 'system' UID, the application is not supposed to have written
132         * anything there.
133         */
134        if (nativeLibraryDir.exists()) {
135            final File[] binaries = nativeLibraryDir.listFiles();
136            if (binaries != null) {
137                for (int nn = 0; nn < binaries.length; nn++) {
138                    if (DEBUG_NATIVE) {
139                        Slog.d(TAG, "    Deleting " + binaries[nn].getName());
140                    }
141
142                    if (!binaries[nn].delete()) {
143                        Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath());
144                    } else {
145                        deletedFiles = true;
146                    }
147                }
148            }
149            // Do not delete 'lib' directory itself, or this will prevent
150            // installation of future updates.
151        }
152
153        return deletedFiles;
154    }
155
156    // We don't care about the other return values for now.
157    private static final int BITCODE_PRESENT = 1;
158
159    public static boolean hasRenderscriptBitcode(ApkHandle handle) throws IOException {
160        final int returnVal = hasRenderscriptBitcode(handle.apkHandle);
161        if (returnVal < 0) {
162            throw new IOException("Error scanning APK, code: " + returnVal);
163        }
164
165        return (returnVal == BITCODE_PRESENT);
166    }
167
168    private static native int hasRenderscriptBitcode(long apkHandle);
169}
170