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