11ebd74acf9977daa42133507e970dab88e08f0efKenny Root/*
21ebd74acf9977daa42133507e970dab88e08f0efKenny Root * Copyright (C) 2010 The Android Open Source Project
31ebd74acf9977daa42133507e970dab88e08f0efKenny Root *
41ebd74acf9977daa42133507e970dab88e08f0efKenny Root * Licensed under the Apache License, Version 2.0 (the "License");
51ebd74acf9977daa42133507e970dab88e08f0efKenny Root * you may not use this file except in compliance with the License.
61ebd74acf9977daa42133507e970dab88e08f0efKenny Root * You may obtain a copy of the License at
71ebd74acf9977daa42133507e970dab88e08f0efKenny Root *
81ebd74acf9977daa42133507e970dab88e08f0efKenny Root *      http://www.apache.org/licenses/LICENSE-2.0
91ebd74acf9977daa42133507e970dab88e08f0efKenny Root *
101ebd74acf9977daa42133507e970dab88e08f0efKenny Root * Unless required by applicable law or agreed to in writing, software
111ebd74acf9977daa42133507e970dab88e08f0efKenny Root * distributed under the License is distributed on an "AS IS" BASIS,
121ebd74acf9977daa42133507e970dab88e08f0efKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131ebd74acf9977daa42133507e970dab88e08f0efKenny Root * See the License for the specific language governing permissions and
141ebd74acf9977daa42133507e970dab88e08f0efKenny Root * limitations under the License.
151ebd74acf9977daa42133507e970dab88e08f0efKenny Root */
161ebd74acf9977daa42133507e970dab88e08f0efKenny Root
1785387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Rootpackage com.android.internal.content;
1885387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root
1973767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS;
2073767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkeyimport static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
2173767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkeyimport static android.content.pm.PackageManager.NO_NATIVE_LIBRARIES;
22bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkeyimport static android.system.OsConstants.S_IRGRP;
23bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkeyimport static android.system.OsConstants.S_IROTH;
24bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkeyimport static android.system.OsConstants.S_IRWXU;
25bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkeyimport static android.system.OsConstants.S_IXGRP;
26bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkeyimport static android.system.OsConstants.S_IXOTH;
2773767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey
28941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkeyimport android.content.pm.ApplicationInfo;
291378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghiimport android.content.pm.PackageManager;
3073767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkeyimport android.content.pm.PackageParser;
318d479b0c2ddb150182bcf510876a240cb869661bJeff Sharkeyimport android.content.pm.PackageParser.Package;
3273767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkeyimport android.content.pm.PackageParser.PackageLite;
3373767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkeyimport android.content.pm.PackageParser.PackageParserException;
34bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkeyimport android.os.Build;
35bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkeyimport android.os.SELinux;
36bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkeyimport android.system.ErrnoException;
37bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkeyimport android.system.Os;
3885387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Rootimport android.util.Slog;
3985387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root
4073767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkeyimport dalvik.system.CloseGuard;
41bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkeyimport dalvik.system.VMRuntime;
4273767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey
43cef0b39b9211882f59b6bfe1148e2cd247056693Narayan Kamathimport java.io.Closeable;
4485387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Rootimport java.io.File;
45d47e38b6342fea93b007319431634a4bcfee452cNarayan Kamathimport java.io.IOException;
4673767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkeyimport java.util.List;
4785387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root
4885387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root/**
4985387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root * Native libraries helper.
5085387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root *
5185387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root * @hide
5285387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root */
5385387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Rootpublic class NativeLibraryHelper {
5485387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root    private static final String TAG = "NativeHelper";
5585387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root    private static final boolean DEBUG_NATIVE = false;
5685387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root
57941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    public static final String LIB_DIR_NAME = "lib";
58941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    public static final String LIB64_DIR_NAME = "lib64";
59941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey
60bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    // Special value for {@code PackageParser.Package#cpuAbiOverride} to indicate
61bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    // that the cpuAbiOverride must be clear.
62bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    public static final String CLEAR_ABI_OVERRIDE = "-";
63bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
641378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi    /**
6573767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey     * A handle to an opened package, consisting of one or more APKs. Used as
6673767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey     * input to the various NativeLibraryHelper methods. Allows us to scan and
6773767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey     * parse the APKs exactly once instead of doing it multiple times.
681378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi     *
691378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi     * @hide
701378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi     */
7173767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey    public static class Handle implements Closeable {
7273767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        private final CloseGuard mGuard = CloseGuard.get();
7373767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        private volatile boolean mClosed;
7473767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey
7573767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        final long[] apkHandles;
76941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        final boolean multiArch;
7773767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey
7873767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        public static Handle create(File packageFile) throws IOException {
7973767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            try {
80be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey                final PackageLite lite = PackageParser.parsePackageLite(packageFile, 0);
81be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey                return create(lite);
8273767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            } catch (PackageParserException e) {
8373767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                throw new IOException("Failed to parse package: " + packageFile, e);
84cef0b39b9211882f59b6bfe1148e2cd247056693Narayan Kamath            }
85be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey        }
86cef0b39b9211882f59b6bfe1148e2cd247056693Narayan Kamath
878d479b0c2ddb150182bcf510876a240cb869661bJeff Sharkey        public static Handle create(Package pkg) throws IOException {
88941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            return create(pkg.getAllCodePaths(),
89941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0);
908d479b0c2ddb150182bcf510876a240cb869661bJeff Sharkey        }
918d479b0c2ddb150182bcf510876a240cb869661bJeff Sharkey
92be520fba1e45c77ca20eb66005a0cf19e10939a1Jeff Sharkey        public static Handle create(PackageLite lite) throws IOException {
93941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            return create(lite.getAllCodePaths(), lite.multiArch);
948d479b0c2ddb150182bcf510876a240cb869661bJeff Sharkey        }
958d479b0c2ddb150182bcf510876a240cb869661bJeff Sharkey
96941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        private static Handle create(List<String> codePaths, boolean multiArch) throws IOException {
9773767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            final int size = codePaths.size();
9873767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            final long[] apkHandles = new long[size];
9973767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            for (int i = 0; i < size; i++) {
10073767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                final String path = codePaths.get(i);
10173767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                apkHandles[i] = nativeOpenApk(path);
10273767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                if (apkHandles[i] == 0) {
10373767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                    // Unwind everything we've opened so far
10473767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                    for (int j = 0; j < i; j++) {
10573767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                        nativeClose(apkHandles[j]);
10673767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                    }
10773767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                    throw new IOException("Unable to open APK: " + path);
10873767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                }
10973767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            }
110cef0b39b9211882f59b6bfe1148e2cd247056693Narayan Kamath
111941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            return new Handle(apkHandles, multiArch);
1121378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi        }
1131378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi
114941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        Handle(long[] apkHandles, boolean multiArch) {
11573767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            this.apkHandles = apkHandles;
116941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            this.multiArch = multiArch;
11773767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            mGuard.open("close");
1181378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi        }
1191378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi
120cef0b39b9211882f59b6bfe1148e2cd247056693Narayan Kamath        @Override
1211378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi        public void close() {
12273767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            for (long apkHandle : apkHandles) {
12373767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                nativeClose(apkHandle);
12473767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            }
12573767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            mGuard.close();
12673767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            mClosed = true;
1271378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi        }
1281378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi
12973767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        @Override
13073767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        protected void finalize() throws Throwable {
13173767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            if (mGuard != null) {
13273767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                mGuard.warnIfOpen();
13373767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            }
13473767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            try {
13573767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                if (!mClosed) {
13673767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                    close();
13773767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                }
13873767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            } finally {
13973767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                super.finalize();
14073767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            }
14173767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        }
14273767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey    }
1431378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi
1441378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi    private static native long nativeOpenApk(String path);
1451378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi    private static native void nativeClose(long handle);
1461378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi
1471378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi    private static native long nativeSumNativeBinaries(long handle, String cpuAbi);
14885387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root
149bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    private native static int nativeCopyNativeBinaries(long handle,
150bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            String sharedLibraryPath, String abiToCopy);
151bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
152bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    private static long sumNativeBinaries(Handle handle, String abi) {
15373767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        long sum = 0;
15473767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        for (long apkHandle : handle.apkHandles) {
155bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            sum += nativeSumNativeBinaries(apkHandle, abi);
15673767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        }
15773767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        return sum;
15885387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root    }
15985387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root
1601ebd74acf9977daa42133507e970dab88e08f0efKenny Root    /**
1611ebd74acf9977daa42133507e970dab88e08f0efKenny Root     * Copies native binaries to a shared library directory.
1621ebd74acf9977daa42133507e970dab88e08f0efKenny Root     *
1631378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi     * @param handle APK file to scan for native libraries
1641ebd74acf9977daa42133507e970dab88e08f0efKenny Root     * @param sharedLibraryDir directory for libraries to be copied to
1651ebd74acf9977daa42133507e970dab88e08f0efKenny Root     * @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another
1661ebd74acf9977daa42133507e970dab88e08f0efKenny Root     *         error code from that class if not
1671ebd74acf9977daa42133507e970dab88e08f0efKenny Root     */
168941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) {
16973767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        for (long apkHandle : handle.apkHandles) {
17073767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi);
17173767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            if (res != INSTALL_SUCCEEDED) {
17273767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                return res;
17373767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            }
17473767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        }
17573767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        return INSTALL_SUCCEEDED;
17685387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root    }
1778f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root
1781378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi    /**
1791378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi     * Checks if a given APK contains native code for any of the provided
1801378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi     * {@code supportedAbis}. Returns an index into {@code supportedAbis} if a matching
1811378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi     * ABI is found, {@link PackageManager#NO_NATIVE_LIBRARIES} if the
1821378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi     * APK doesn't contain any native code, and
1831378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi     * {@link PackageManager#INSTALL_FAILED_NO_MATCHING_ABIS} if none of the ABIs match.
1841378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi     */
18573767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey    public static int findSupportedAbi(Handle handle, String[] supportedAbis) {
18673767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        int finalRes = NO_NATIVE_LIBRARIES;
18773767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        for (long apkHandle : handle.apkHandles) {
18873767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            final int res = nativeFindSupportedAbi(apkHandle, supportedAbis);
18973767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            if (res == NO_NATIVE_LIBRARIES) {
19073767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                // No native code, keep looking through all APKs.
19173767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            } else if (res == INSTALL_FAILED_NO_MATCHING_ABIS) {
19273767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                // Found some native code, but no ABI match; update our final
19373767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                // result if we haven't found other valid code.
19473767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                if (finalRes < 0) {
19573767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                    finalRes = INSTALL_FAILED_NO_MATCHING_ABIS;
19673767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                }
19773767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            } else if (res >= 0) {
19873767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                // Found valid native code, track the best ABI match
19973767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                if (finalRes < 0 || res < finalRes) {
20073767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                    finalRes = res;
20173767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                }
20273767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            } else {
20373767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                // Unexpected error; bail
20473767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                return res;
20573767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            }
20673767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        }
20773767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        return finalRes;
2081378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi    }
2091378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi
2101378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi    private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis);
2111378aba7aeeb7f6dd6cc2503968ba7b0e58d9333Ramin Zaghi
212831baa2e2566bf1d243c06918672abd5ff786105Kenny Root    // Convenience method to call removeNativeBinariesFromDirLI(File)
213ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath    public static void removeNativeBinariesLI(String nativeLibraryPath) {
214ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath        if (nativeLibraryPath == null) return;
215ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath        removeNativeBinariesFromDirLI(new File(nativeLibraryPath), false /* delete root dir */);
216831baa2e2566bf1d243c06918672abd5ff786105Kenny Root    }
217831baa2e2566bf1d243c06918672abd5ff786105Kenny Root
218ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath    /**
219ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath     * Remove the native binaries of a given package. This deletes the files
220ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath     */
221ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath    public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot, boolean deleteRootDir) {
2228f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root        if (DEBUG_NATIVE) {
223ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath            Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryRoot.getPath());
2248f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root        }
2258f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root
2268f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root        /*
2278f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root         * Just remove any file in the directory. Since the directory is owned
2288f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root         * by the 'system' UID, the application is not supposed to have written
2298f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root         * anything there.
2308f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root         */
231ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath        if (nativeLibraryRoot.exists()) {
232ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath            final File[] files = nativeLibraryRoot.listFiles();
233ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath            if (files != null) {
234ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath                for (int nn = 0; nn < files.length; nn++) {
2358f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root                    if (DEBUG_NATIVE) {
236ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath                        Slog.d(TAG, "    Deleting " + files[nn].getName());
2378f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root                    }
238831baa2e2566bf1d243c06918672abd5ff786105Kenny Root
239ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath                    if (files[nn].isDirectory()) {
240ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath                        removeNativeBinariesFromDirLI(files[nn], true /* delete root dir */);
241ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath                    } else if (!files[nn].delete()) {
242ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath                        Slog.w(TAG, "Could not delete native binary: " + files[nn].getPath());
2438f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root                    }
2448f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root                }
2458f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root            }
246ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath            // Do not delete 'lib' directory itself, unless we're specifically
247ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath            // asked to or this will prevent installation of future updates.
248ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath            if (deleteRootDir) {
249ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath                if (!nativeLibraryRoot.delete()) {
250ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath                    Slog.w(TAG, "Could not delete native binary directory: " + nativeLibraryRoot.getPath());
251ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath                }
252ff110bd61a69f7ed8602ae14b27f7befec76b2e7Narayan Kamath            }
2538f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root        }
2548f7cc02c7c4bd542376648dbd54be3ceb8521f73Kenny Root    }
255d47e38b6342fea93b007319431634a4bcfee452cNarayan Kamath
256bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    private static void createNativeLibrarySubdir(File path) throws IOException {
257bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        if (!path.isDirectory()) {
258bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            path.delete();
259bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
260bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            if (!path.mkdir()) {
261bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                throw new IOException("Cannot create " + path.getPath());
262bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            }
263bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
264bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            try {
265bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                Os.chmod(path.getPath(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
266bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            } catch (ErrnoException e) {
267bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                throw new IOException("Cannot chmod native library directory "
268bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                        + path.getPath(), e);
269bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            }
270bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        } else if (!SELinux.restorecon(path)) {
271bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            throw new IOException("Cannot set SELinux context for " + path.getPath());
272bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        }
273bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    }
274bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
275941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    private static long sumNativeBinariesForSupportedAbi(Handle handle, String[] abiList) {
276bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        int abi = findSupportedAbi(handle, abiList);
277bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        if (abi >= 0) {
278bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            return sumNativeBinaries(handle, abiList[abi]);
279bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        } else {
280bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            return 0;
281bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        }
282bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    }
283bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
284941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    public static int copyNativeBinariesForSupportedAbi(Handle handle, File libraryRoot,
285bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            String[] abiList, boolean useIsaSubdir) throws IOException {
286bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        createNativeLibrarySubdir(libraryRoot);
287bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
288bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        /*
289bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey         * If this is an internal application or our nativeLibraryPath points to
290bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey         * the app-lib directory, unpack the libraries if necessary.
291bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey         */
292bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        int abi = findSupportedAbi(handle, abiList);
293bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        if (abi >= 0) {
294bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            /*
295bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey             * If we have a matching instruction set, construct a subdir under the native
296bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey             * library root that corresponds to this instruction set.
297bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey             */
298bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            final String instructionSet = VMRuntime.getInstructionSet(abiList[abi]);
299bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            final File subDir;
300bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            if (useIsaSubdir) {
301bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                final File isaSubdir = new File(libraryRoot, instructionSet);
302bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                createNativeLibrarySubdir(isaSubdir);
303bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                subDir = isaSubdir;
304bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            } else {
305bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                subDir = libraryRoot;
306bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            }
307bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
308941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            int copyRet = copyNativeBinaries(handle, subDir, abiList[abi]);
309bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            if (copyRet != PackageManager.INSTALL_SUCCEEDED) {
310bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                return copyRet;
311bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            }
312bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        }
313bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
314bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        return abi;
315bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    }
316bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
317941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    public static int copyNativeBinariesWithOverride(Handle handle, File libraryRoot,
318941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            String abiOverride) {
319bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        try {
320941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            if (handle.multiArch) {
321bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                // Warn if we've set an abiOverride for multi-lib packages..
322bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                // By definition, we need to copy both 32 and 64 bit libraries for
323bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                // such packages.
324bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                if (abiOverride != null && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
325bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                    Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
326bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                }
327bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
328bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                int copyRet = PackageManager.NO_NATIVE_LIBRARIES;
329bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
330941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot,
331bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                            Build.SUPPORTED_32_BIT_ABIS, true /* use isa specific subdirs */);
332bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                    if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
333bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                            copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
334bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                        Slog.w(TAG, "Failure copying 32 bit native libraries; copyRet=" +copyRet);
335bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                        return copyRet;
336bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                    }
337bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                }
338bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
339bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
340941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                    copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot,
341bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                            Build.SUPPORTED_64_BIT_ABIS, true /* use isa specific subdirs */);
342bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                    if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES &&
343bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                            copyRet != PackageManager.INSTALL_FAILED_NO_MATCHING_ABIS) {
344bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                        Slog.w(TAG, "Failure copying 64 bit native libraries; copyRet=" +copyRet);
345bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                        return copyRet;
346bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                    }
347bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                }
348bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            } else {
349bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                String cpuAbiOverride = null;
350bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
351bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                    cpuAbiOverride = null;
352bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                } else if (abiOverride != null) {
353bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                    cpuAbiOverride = abiOverride;
354bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                }
355bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
356bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                String[] abiList = (cpuAbiOverride != null) ?
357bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                        new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
358bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&
359bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                        hasRenderscriptBitcode(handle)) {
360bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                    abiList = Build.SUPPORTED_32_BIT_ABIS;
361bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                }
362bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
363941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                int copyRet = copyNativeBinariesForSupportedAbi(handle, libraryRoot, abiList,
364bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                        true /* use isa specific subdirs */);
365bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                if (copyRet < 0 && copyRet != PackageManager.NO_NATIVE_LIBRARIES) {
366bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                    Slog.w(TAG, "Failure copying native libraries [errorCode=" + copyRet + "]");
367bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                    return copyRet;
368bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                }
369bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            }
370bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
371bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            return PackageManager.INSTALL_SUCCEEDED;
372bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        } catch (IOException e) {
373bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            Slog.e(TAG, "Copying native libraries failed", e);
374bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
375bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        }
376bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    }
377bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
378941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey    public static long sumNativeBinariesWithOverride(Handle handle, String abiOverride)
379bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            throws IOException {
380bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        long sum = 0;
381941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey        if (handle.multiArch) {
382bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // Warn if we've set an abiOverride for multi-lib packages..
383bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // By definition, we need to copy both 32 and 64 bit libraries for
384bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            // such packages.
385bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            if (abiOverride != null && !CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
386bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                Slog.w(TAG, "Ignoring abiOverride for multi arch application.");
387bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            }
388bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
389bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
390941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                sum += sumNativeBinariesForSupportedAbi(handle, Build.SUPPORTED_32_BIT_ABIS);
391bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            }
392bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
393bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
394941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey                sum += sumNativeBinariesForSupportedAbi(handle, Build.SUPPORTED_64_BIT_ABIS);
395bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            }
396bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        } else {
397bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            String cpuAbiOverride = null;
398bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            if (CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
399bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                cpuAbiOverride = null;
400bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            } else if (abiOverride != null) {
401bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                cpuAbiOverride = abiOverride;
402bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            }
403bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
404bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            String[] abiList = (cpuAbiOverride != null) ?
405bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                    new String[] { cpuAbiOverride } : Build.SUPPORTED_ABIS;
406bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            if (Build.SUPPORTED_64_BIT_ABIS.length > 0 && cpuAbiOverride == null &&
407bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                    hasRenderscriptBitcode(handle)) {
408bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey                abiList = Build.SUPPORTED_32_BIT_ABIS;
409bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey            }
410bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
411941a8ba1a6043cf84a7bf622e44a0b4f7abd0178Jeff Sharkey            sum += sumNativeBinariesForSupportedAbi(handle, abiList);
412bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        }
413bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey        return sum;
414bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    }
415bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
416d47e38b6342fea93b007319431634a4bcfee452cNarayan Kamath    // We don't care about the other return values for now.
417d47e38b6342fea93b007319431634a4bcfee452cNarayan Kamath    private static final int BITCODE_PRESENT = 1;
418d47e38b6342fea93b007319431634a4bcfee452cNarayan Kamath
419bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey    private static native int hasRenderscriptBitcode(long apkHandle);
420bb7b7bea19223c1eba74f525c7fe87ca3911813bJeff Sharkey
42173767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey    public static boolean hasRenderscriptBitcode(Handle handle) throws IOException {
42273767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        for (long apkHandle : handle.apkHandles) {
42373767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            final int res = hasRenderscriptBitcode(apkHandle);
42473767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            if (res < 0) {
42573767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                throw new IOException("Error scanning APK, code: " + res);
42673767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            } else if (res == BITCODE_PRESENT) {
42773767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey                return true;
42873767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey            }
429d47e38b6342fea93b007319431634a4bcfee452cNarayan Kamath        }
43073767b9d607d99b3a027619b5c6b7f1a09b7673dJeff Sharkey        return false;
431d47e38b6342fea93b007319431634a4bcfee452cNarayan Kamath    }
43285387d7ba36e56b291cbde87acb5a5b2200fe01cKenny Root}
433