1effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// found in the LICENSE file.
4effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
5effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
6effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochpackage org.chromium.base.library_loader;
7effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
8effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport android.content.Context;
9effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport android.content.pm.ApplicationInfo;
10effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport android.os.Build;
11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport android.util.Log;
12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport java.io.File;
14effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport java.io.FileOutputStream;
15effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport java.io.IOException;
16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport java.io.InputStream;
17effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport java.util.zip.ZipEntry;
18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochimport java.util.zip.ZipFile;
19effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
20effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch/**
21effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * The class provides helper functions to extract native libraries from APK,
22effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * and load libraries from there.
23effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch *
24effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * The class should be package-visible only, but made public for testing
25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * purpose.
26effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch */
27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochpublic class LibraryLoaderHelper {
28effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private static final String TAG = "LibraryLoaderHelper";
29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private static final String LIB_DIR = "lib";
31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
32effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    /**
33effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * One-way switch becomes true if native libraries were unpacked
34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * from APK.
35effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     */
36effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private static boolean sLibrariesWereUnpacked = false;
37effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    /**
39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * Loads native libraries using workaround only, skip the library in system
40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * lib path. The method exists only for testing purpose.
41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * Caller must ensure thread safety of this method.
42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * @param context
43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     */
44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    public static boolean loadNativeLibrariesUsingWorkaroundForTesting(Context context) {
45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // Although tryLoadLibraryUsingWorkaround might be called multiple times,
46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // libraries should only be unpacked once, this is guaranteed by
47effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // sLibrariesWereUnpacked.
48effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        for (String library : NativeLibraries.LIBRARIES) {
49effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            if (!tryLoadLibraryUsingWorkaround(context, library)) {
50effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                return false;
51effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            }
52effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        }
53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        return true;
54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
55effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    /**
57effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * Try to load a native library using a workaround of
58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *   http://b/13216167.
59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *
60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * Workaround for b/13216167 was adapted from code in
61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * https://googleplex-android-review.git.corp.google.com/#/c/433061
62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *
63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * More details about http://b/13216167:
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *   PackageManager may fail to update shared library.
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * Native library directory in an updated package is a symbolic link
67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * to a directory in /data/app-lib/<package name>, for example:
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * /data/data/com.android.chrome/lib -> /data/app-lib/com.android.chrome[-1].
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * When updating the application, the PackageManager create a new directory,
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * e.g., /data/app-lib/com.android.chrome-2, and remove the old symlink and
71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * recreate one to the new directory. However, on some devices (e.g. Sony Xperia),
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * the symlink was updated, but fails to extract new native libraries from
73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * the new apk.
74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * We make the following changes to alleviate the issue:
76effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *  1) name the native library with apk version code, e.g.,
77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *     libchrome.1750.136.so, 1750.136 is Chrome version number;
78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *  2) first try to load the library using System.loadLibrary,
79effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *     if that failed due to the library file was not found,
80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *     search the named library in a /data/data/com.android.chrome/app_lib
81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *     directory. Because of change 1), each version has a different native
82effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *     library name, so avoid mistakenly using the old native library.
83effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *
84effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *  If named library is not in /data/data/com.android.chrome/app_lib directory,
85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *  extract native libraries from apk and cache in the directory.
86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *
87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * This function doesn't throw UnsatisfiedLinkError, the caller needs to
88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * check the return value.
89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     */
90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    static boolean tryLoadLibraryUsingWorkaround(Context context, String library) {
91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        assert context != null;
92effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        File libFile = getWorkaroundLibFile(context, library);
93effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        if (!libFile.exists() && !unpackLibrariesOnce(context)) {
94effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            return false;
95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        }
96effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        try {
97effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            System.load(libFile.getAbsolutePath());
98effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            return true;
99effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        } catch (UnsatisfiedLinkError e) {
100effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            return false;
101effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        }
102effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
103effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
104effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    /**
105effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * Returns the directory for holding extracted native libraries.
106effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * It may create the directory if it doesn't exist.
107effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *
108effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * @param context
109effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * @return the directory file object
110effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     */
111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    public static File getWorkaroundLibDir(Context context) {
112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        return context.getDir(LIB_DIR, Context.MODE_PRIVATE);
113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private static File getWorkaroundLibFile(Context context, String library) {
116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        String libName = System.mapLibraryName(library);
117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        return new File(getWorkaroundLibDir(context), libName);
118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    /**
121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * Unpack native libraries from the APK file. The method is supposed to
122effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * be called only once. It deletes existing files in unpacked directory
123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * before unpacking.
124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *
125effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * @param context
126effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * @return true when unpacking was successful, false when failed or called
127effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *         more than once.
128effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     */
129effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private static boolean unpackLibrariesOnce(Context context) {
130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        if (sLibrariesWereUnpacked) {
131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            return false;
132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        }
133effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        sLibrariesWereUnpacked = true;
134effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        File libDir = getWorkaroundLibDir(context);
136c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        deleteDirectorySync(libDir);
137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
138effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        try {
139effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            ApplicationInfo appInfo = context.getApplicationInfo();
140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            ZipFile file = new ZipFile(new File(appInfo.sourceDir), ZipFile.OPEN_READ);
141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            for (String libName : NativeLibraries.LIBRARIES) {
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                String jniNameInApk = getJniNameInApk(libName);
143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
144effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                final ZipEntry entry = file.getEntry(jniNameInApk);
145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                if (entry == null) {
146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    Log.e(TAG, appInfo.sourceDir + " doesn't have file " + jniNameInApk);
147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    file.close();
148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    deleteDirectorySync(libDir);
149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    return false;
150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                }
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                File outputFile = getWorkaroundLibFile(context, libName);
153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                Log.i(TAG, "Extracting native libraries into " + outputFile.getAbsolutePath());
155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
156effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                assert !outputFile.exists();
157effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
158effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                try {
159effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    if (!outputFile.createNewFile()) {
160effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        throw new IOException();
161effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    }
162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    InputStream is = null;
164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    FileOutputStream os = null;
165effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    try {
166effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        is = file.getInputStream(entry);
167effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        os = new FileOutputStream(outputFile);
168effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        int count = 0;
169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        byte[] buffer = new byte[16 * 1024];
170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        while ((count = is.read(buffer)) > 0) {
171effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            os.write(buffer, 0, count);
172effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        }
173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    } finally {
174effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        try {
175effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            if (is != null) is.close();
176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        } finally {
177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            if (os != null) os.close();
178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        }
179effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    }
180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    // Change permission to rwxr-xr-x
181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    outputFile.setReadable(true, false);
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    outputFile.setExecutable(true, false);
183effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    outputFile.setWritable(true);
184effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                } catch (IOException e) {
185effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    if (outputFile.exists()) {
186effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        if (!outputFile.delete()) {
187effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            Log.e(TAG, "Failed to delete " + outputFile.getAbsolutePath());
188effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        }
189effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    }
190effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    file.close();
191effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    throw e;
192effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                }
193effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            }
194effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            file.close();
195effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            return true;
196effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        } catch (IOException e) {
197effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            Log.e(TAG, "Failed to unpack native libraries", e);
198effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            deleteDirectorySync(libDir);
199effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            return false;
200effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        }
201effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
202effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
203effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    /**
204effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * Delete old library files in the backup directory.
205effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *  The actual deletion is done in a background thread.
206effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     *
207effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * @param context
208effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     */
209c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    static void deleteWorkaroundLibrariesAsynchronously(final Context context) {
210effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        // Child process should not reach here.
211c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        new Thread() {
212c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            @Override
213c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            public void run() {
214c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                deleteWorkaroundLibrariesSynchronously(context);
215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            }
216c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        }.start();
217effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
218effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
219effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    /**
220effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * Delete the workaround libraries and directory synchronously.
221effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * For testing purpose only.
222effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     * @param context
223effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch     */
224effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    public static void deleteWorkaroundLibrariesSynchronously(Context context) {
225effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        File libDir = getWorkaroundLibDir(context);
226c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        deleteDirectorySync(libDir);
227effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
228effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    @SuppressWarnings("deprecation")
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    private static String getJniNameInApk(String libName) {
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        // TODO(aurimas): Build.CPU_ABI has been deprecated. Replace it when final L SDK is public.
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return "lib/" + Build.CPU_ABI + "/" + System.mapLibraryName(libName);
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
235effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    private static void deleteDirectorySync(File dir) {
236effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        try {
237effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            File[] files = dir.listFiles();
238effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            if (files != null) {
239effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                for (File file : files) {
240effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    if (!file.delete()) {
241effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                      Log.e(TAG, "Failed to remove " + file.getAbsolutePath());
242effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                    }
243effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                }
244effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            }
245effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            if (!dir.delete()) {
246effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                Log.w(TAG, "Failed to remove " + dir.getAbsolutePath());
247effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            }
248effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            return;
249effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        } catch (Exception e) {
250effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch            Log.e(TAG, "Failed to remove old libs, ", e);
251effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        }
252effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
253effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
254