Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(762)

Unified Diff: base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java

Issue 200753002: [Android] Workaround of an android platform bug. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix a build error. Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..27c196b1acb7272f8fd8874f13d5635103b4f930
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java
@@ -0,0 +1,188 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+package org.chromium.base.library_loader;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.Build;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+class LibraryLoaderHelper {
+ private static final String TAG = "LibraryLoaderHelper";
+
+ private static final String LIB_DIR = "lib";
+
+ /**
+ * Try to load a native library using a workaround of
+ * http://b/13216167.
+ *
+ * Workaround for b/13216167 was adapted from code in
+ * https://googleplex-android-review.git.corp.google.com/#/c/433061
+ *
+ * More details about http://b/13216167:
+ * PackageManager may fail to update shared library.
+ *
+ * Native library directory in an updated package is a symbolic link
+ * to a directory in /data/app-lib/<package name>, for example:
+ * /data/data/com.android.chrome/lib -> /data/app-lib/com.android.chrome[-1].
+ * When updating the application, the PackageManager create a new directory,
+ * e.g., /data/app-lib/com.android.chrome-2, and remove the old symlink and
+ * recreate one to the new directory. However, on some devices (e.g. Sony Xperia),
+ * the symlink was updated, but fails to extract new native libraries from
+ * the new apk.
+
+ * We make the following changes to alleviate the issue:
+ * 1) name the native library with apk version code, e.g.,
+ * libchrome.1750.136.so, 1750.136 is Chrome version number;
+ * 2) first try to load the library using System.loadLibrary,
+ * if that failed due to the file was not found,
+ * search the named library in a backup directory.
+ * Because of change 1, each version has a different native
+ * library name, so avoids mistakenly using the old native library.
+ *
+ * If named library is not in backup directory, extract native libraries
+ * from apk.
+ *
+ * This function doesn't throw UnsatisfiedLinkError, the caller needs to
+ * check the return value.
+ */
+ static boolean tryLoadLibraryUsingWorkaround(
+ Context context, String library, boolean shouldUnpack) {
+ File libFile = getWorkaroundLibFile(context, library);
+ if (!libFile.exists() && shouldUnpack && !unpackLibraries(context)) {
+ return false;
+ }
+ try {
+ System.load(libFile.getAbsolutePath());
+ return true;
+ } catch (UnsatisfiedLinkError e) {
+ return false;
+ }
+ }
+
+ private static File getWorkaroundLibFile(Context context, String library) {
+ String libName = System.mapLibraryName(library);
+ return new File(context.getDir(LIB_DIR, Context.MODE_PRIVATE),
+ libName);
+ }
+
+ private static boolean unpackLibraries(Context context) {
+ try {
+ ApplicationInfo appInfo = context.getApplicationInfo();
+ ZipFile file = new ZipFile(new File(appInfo.sourceDir), ZipFile.OPEN_READ);
+ for (String libName : NativeLibraries.LIBRARIES) {
+ String jniNameInApk = "lib/" + Build.CPU_ABI + "/" +
+ System.mapLibraryName(libName);
+
+ final ZipEntry entry = file.getEntry(jniNameInApk);
+ if (entry == null) {
+ Log.e(TAG, appInfo.sourceDir + " doesn't have file " + jniNameInApk);
+ file.close();
+ return false;
+ }
+
+ File outputFile = getWorkaroundLibFile(context, libName);
+
+ Log.i(TAG, "Extracting native libraries into " + outputFile.getAbsolutePath());
+
+ assert !outputFile.exists();
+
+ try {
+ outputFile.createNewFile();
+
+ InputStream is = null;
+ FileOutputStream os = null;
+ try {
+ is = file.getInputStream(entry);
+ os = new FileOutputStream(outputFile);
+ int count = 0;
+ byte[] buffer = new byte[4096];
+ while ((count = is.read(buffer)) > 0) {
+ os.write(buffer, 0, count);
+ }
+ } finally {
+ if (is != null) is.close();
+ if (os != null) os.close();
+ }
+ // Change permission to rwxr-xr-x
+ outputFile.setReadable(true, false);
+ outputFile.setExecutable(true, false);
+ outputFile.setWritable(true);
+ } catch (IOException e) {
+ if (outputFile.exists()) {
+ outputFile.delete();
+ }
+ file.close();
+ throw e;
+ }
+ }
+ file.close();
+ return true;
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to unpack native libraries", e);
+ return false;
+ }
+ }
+
+ /**
+ * Delete old library files in the backup directory.
+ * The actual deletion is done in a background thread.
+ *
+ * @param context
+ * @param removeDir if true, deletes the directory
+ */
+ static void cleanupOldLibraries(Context context, final boolean deleteDir) {
+ // Child process should not reach here.
+ final File libDir = context.getDir(LIB_DIR, Context.MODE_PRIVATE);
+ if (libDir.exists() && libDir.isDirectory()) {
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ Set<String> filesToKeep =
+ new HashSet<String>(NativeLibraries.LIBRARIES.length);
+ if (!deleteDir) {
+ for (String libName : NativeLibraries.LIBRARIES) {
+ filesToKeep.add(System.mapLibraryName(libName));
+ }
+ }
+
+ File[] files = libDir.listFiles();
+ if (files != null) {
+ for (File file : files) {
+ String fileName = file.getName();
+ if (filesToKeep.contains(fileName)) {
+ continue;
+ } else {
+ if (!file.delete()) {
+ Log.e(TAG, "Failed to remove " + file.getAbsolutePath());
+ }
+ }
+ }
+ }
+ if (deleteDir) {
+ if (!libDir.delete()) {
+ Log.w(TAG, "Failed to remove " + libDir.getAbsolutePath());
+ }
+ return;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to remove old libs, ", e);
+ }
+ }
+ }.start();
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698