From dd06b74157efa0ebd4980eb79d92b3f0e4be35d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Gregorczyk?= Date: Fri, 8 Jul 2016 13:52:31 -0700 Subject: [PATCH] Make SoLoader an external dependency Reviewed By: bestander Differential Revision: D3535233 fbshipit-source-id: 9fddb654123a7606d46069a98e2f68dec7f520fa --- ReactAndroid/build.gradle | 1 + .../com/facebook/soloader/ApkSoSource.java | 171 ----------- .../soloader/java/com/facebook/soloader/BUCK | 25 +- .../facebook/soloader/DirectorySoSource.java | 76 ----- .../java/com/facebook/soloader/Elf32_Dyn.java | 14 - .../com/facebook/soloader/Elf32_Ehdr.java | 26 -- .../com/facebook/soloader/Elf32_Phdr.java | 20 -- .../com/facebook/soloader/Elf32_Shdr.java | 22 -- .../java/com/facebook/soloader/Elf64_Dyn.java | 14 - .../com/facebook/soloader/Elf64_Ehdr.java | 26 -- .../com/facebook/soloader/Elf64_Phdr.java | 20 -- .../com/facebook/soloader/Elf64_Shdr.java | 22 -- .../com/facebook/soloader/ExoSoSource.java | 177 ----------- .../com/facebook/soloader/FileLocker.java | 48 --- .../java/com/facebook/soloader/MinElf.java | 282 ------------------ .../com/facebook/soloader/NativeLibrary.java | 93 ------ .../com/facebook/soloader/NoopSoSource.java | 28 -- .../java/com/facebook/soloader/SoLoader.java | 237 --------------- .../java/com/facebook/soloader/SoSource.java | 57 ---- .../java/com/facebook/soloader/SysUtil.java | 205 ------------- .../java/com/facebook/soloader/genstructs.sh | 35 --- .../java/com/facebook/soloader/soloader.pro | 6 - 22 files changed, 9 insertions(+), 1596 deletions(-) delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/ApkSoSource.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/DirectorySoSource.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Dyn.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Ehdr.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Phdr.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Shdr.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Dyn.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Ehdr.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Phdr.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Shdr.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/ExoSoSource.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/FileLocker.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/MinElf.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/NativeLibrary.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/NoopSoSource.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SoLoader.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SoSource.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SysUtil.java delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/genstructs.sh delete mode 100644 ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/soloader.pro diff --git a/ReactAndroid/build.gradle b/ReactAndroid/build.gradle index 407316d02..7a142cefe 100644 --- a/ReactAndroid/build.gradle +++ b/ReactAndroid/build.gradle @@ -266,6 +266,7 @@ dependencies { compile 'com.android.support:recyclerview-v7:23.0.1' compile 'com.facebook.fresco:fresco:0.11.0' compile 'com.facebook.fresco:imagepipeline-okhttp3:0.11.0' + compile 'com.facebook.soloader:soloader:0.1.0' compile 'com.fasterxml.jackson.core:jackson-core:2.2.3' compile 'com.google.code.findbugs:jsr305:3.0.0' compile 'com.squareup.okhttp3:okhttp:3.2.0' diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/ApkSoSource.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/ApkSoSource.java deleted file mode 100644 index eba1eeaf5..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/ApkSoSource.java +++ /dev/null @@ -1,171 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.soloader; - -import java.io.File; -import java.io.IOException; -import android.content.Context; - -import java.util.jar.JarFile; -import java.util.jar.JarEntry; - -import java.util.regex.Pattern; -import java.util.regex.Matcher; - -import android.os.Build; -import android.system.Os; -import android.system.ErrnoException; - -import java.util.HashMap; -import java.util.Map; -import java.util.Enumeration; - -import java.io.InputStream; -import java.io.FileOutputStream; - -import android.util.Log; - -/** - * {@link SoSource} that extracts libraries from an APK to the filesystem. - */ -public class ApkSoSource extends DirectorySoSource { - - private static final String TAG = SoLoader.TAG; - private static final boolean DEBUG = SoLoader.DEBUG; - - /** - * Make a new ApkSoSource that extracts DSOs from our APK instead of relying on the system to do - * the extraction for us. - * - * @param context Application context - */ - public ApkSoSource(Context context) throws IOException { - // - // Initialize a normal DirectorySoSource that will load from our extraction directory. At this - // point, the directory may be empty or contain obsolete libraries, but that's okay. - // - - super(SysUtil.createLibsDirectory(context), DirectorySoSource.RESOLVE_DEPENDENCIES); - - // - // Synchronize the contents of that directory with the library payload in our APK, deleting and - // extracting as needed. - // - - try (JarFile apk = new JarFile(context.getApplicationInfo().publicSourceDir)) { - File libsDir = super.soDirectory; - - if (DEBUG) { - Log.v(TAG, "synchronizing log directory: " + libsDir); - } - - Map providedLibraries = findProvidedLibraries(apk); - try (FileLocker lock = SysUtil.lockLibsDirectory(context)) { - // Delete files in libsDir that we don't provide or that are out of date. Forget about any - // libraries that are up-to-date already so we don't unpack them below. - File extantFiles[] = libsDir.listFiles(); - for (int i = 0; i < extantFiles.length; ++i) { - File extantFile = extantFiles[i]; - - if (DEBUG) { - Log.v(TAG, "considering libdir file: " + extantFile); - } - - String name = extantFile.getName(); - SoInfo so = providedLibraries.get(name); - boolean shouldDelete = - (so == null || - so.entry.getSize() != extantFile.length() || - so.entry.getTime() != extantFile.lastModified()); - boolean upToDate = (so != null && !shouldDelete); - - if (shouldDelete) { - if (DEBUG) { - Log.v(TAG, "deleting obsolete or unexpected file: " + extantFile); - } - SysUtil.deleteOrThrow(extantFile); - } - - if (upToDate) { - if (DEBUG) { - Log.v(TAG, "found up-to-date library: " + extantFile); - } - providedLibraries.remove(name); - } - } - - // Now extract any libraries left in providedLibraries; we removed all the up-to-date ones. - for (SoInfo so : providedLibraries.values()) { - JarEntry entry = so.entry; - try (InputStream is = apk.getInputStream(entry)) { - if (DEBUG) { - Log.v(TAG, "extracting library: " + so.soName); - } - SysUtil.reliablyCopyExecutable( - is, - new File(libsDir, so.soName), - entry.getSize(), - entry.getTime()); - } - - SysUtil.freeCopyBuffer(); - } - } - } - } - - /** - * Find the shared libraries provided in this APK and supported on this system. Each returend - * SoInfo points to the most preferred version of that library bundled with the given APK: for - * example, if we're on an armv7-a system and we have both arm and armv7-a versions of libfoo, the - * returned entry for libfoo points to the armv7-a version of libfoo. - * - * The caller owns the returned value and may mutate it. - * - * @param apk Opened application APK file - * @return Map of sonames to SoInfo instances - */ - private static Map findProvidedLibraries(JarFile apk) { - // Subgroup 1: ABI. Subgroup 2: soname. - Pattern libPattern = Pattern.compile("^lib/([^/]+)/([^/]+\\.so)$"); - HashMap providedLibraries = new HashMap<>(); - String[] supportedAbis = SysUtil.getSupportedAbis(); - Enumeration entries = apk.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = entries.nextElement(); - Matcher m = libPattern.matcher(entry.getName()); - if (m.matches()) { - String libraryAbi = m.group(1); - String soName = m.group(2); - int abiScore = SysUtil.findAbiScore(supportedAbis, libraryAbi); - if (abiScore >= 0) { - SoInfo so = providedLibraries.get(soName); - if (so == null || abiScore < so.abiScore) { - providedLibraries.put(soName, new SoInfo(soName, entry, abiScore)); - } - } - } - } - - return providedLibraries; - } - - private static final class SoInfo { - public final String soName; - public final JarEntry entry; - public final int abiScore; - - SoInfo(String soName, JarEntry entry, int abiScore) { - this.soName = soName; - this.entry = entry; - this.abiScore = abiScore; - } - } -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK index 322ba2204..f9c872b0f 100644 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK +++ b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/BUCK @@ -1,20 +1,11 @@ -include_defs('//ReactAndroid/DEFS') - -android_library( - name = 'soloader', - srcs = glob(['*.java']), - proguard_config = 'soloader.pro', - deps = [ - react_native_dep('third-party/java/jsr-305:jsr-305'), - # Be very careful adding new dependencies here, because this code - # has to run very early in the app startup process. - # Definitely do *not* depend on lib-base or guava. - ], - visibility = [ - 'PUBLIC', - ], +android_prebuilt_aar( + name = 'soloader', + aar = ':soloader-binary-aar', + visibility = ['PUBLIC'], ) -project_config( - src_target = ':soloader', +remote_file( + name = 'soloader-binary-aar', + url = 'mvn:com.facebook.soloader:soloader:aar:0.1.0', + sha1 = '918573465c94c6bc9bad48ef259f1e0cd6543c1b', ) diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/DirectorySoSource.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/DirectorySoSource.java deleted file mode 100644 index 47cdb0232..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/DirectorySoSource.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.soloader; - -import java.io.File; -import java.io.IOException; - -/** - * {@link SoSource} that finds shared libraries in a given directory. - */ -public class DirectorySoSource extends SoSource { - - public static final int RESOLVE_DEPENDENCIES = 1; - public static final int ON_LD_LIBRARY_PATH = 2; - - protected final File soDirectory; - private final int flags; - - /** - * Make a new DirectorySoSource. If {@code flags} contains {@code RESOLVE_DEPENDENCIES}, - * recursively load dependencies for shared objects loaded from this directory. (We shouldn't - * need to resolve dependencies for libraries loaded from system directories: the dynamic linker - * is smart enough to do it on its own there.) - */ - public DirectorySoSource(File soDirectory, int flags) { - this.soDirectory = soDirectory; - this.flags = flags; - } - - @Override - public int loadLibrary(String soName, int loadFlags) throws IOException { - File soFile = new File(soDirectory, soName); - if (!soFile.exists()) { - return LOAD_RESULT_NOT_FOUND; - } - - if ((loadFlags & LOAD_FLAG_ALLOW_IMPLICIT_PROVISION) != 0 && - (flags & ON_LD_LIBRARY_PATH) != 0) { - return LOAD_RESULT_IMPLICITLY_PROVIDED; - } - - if ((flags & RESOLVE_DEPENDENCIES) != 0) { - String dependencies[] = MinElf.extract_DT_NEEDED(soFile); - for (int i = 0; i < dependencies.length; ++i) { - String dependency = dependencies[i]; - if (dependency.startsWith("/")) { - continue; - } - - SoLoader.loadLibraryBySoName( - dependency, - (loadFlags | LOAD_FLAG_ALLOW_IMPLICIT_PROVISION)); - } - } - - System.load(soFile.getAbsolutePath()); - return LOAD_RESULT_LOADED; - } - - @Override - public File unpackLibrary(String soName) throws IOException { - File soFile = new File(soDirectory, soName); - if (soFile.exists()) { - return soFile; - } - - return null; - } -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Dyn.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Dyn.java deleted file mode 100644 index a9ec0713d..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Dyn.java +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -// AUTOMATICALLY GENERATED CODE. Regenerate with genstructs.sh. -package com.facebook.soloader; -public final class Elf32_Dyn { - public static final int d_tag = 0x0; - public static final int d_un = 0x4; -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Ehdr.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Ehdr.java deleted file mode 100644 index a398ffe78..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Ehdr.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -// AUTOMATICALLY GENERATED CODE. Regenerate with genstructs.sh. -package com.facebook.soloader; -public final class Elf32_Ehdr { - public static final int e_ident = 0x0; - public static final int e_type = 0x10; - public static final int e_machine = 0x12; - public static final int e_version = 0x14; - public static final int e_entry = 0x18; - public static final int e_phoff = 0x1c; - public static final int e_shoff = 0x20; - public static final int e_flags = 0x24; - public static final int e_ehsize = 0x28; - public static final int e_phentsize = 0x2a; - public static final int e_phnum = 0x2c; - public static final int e_shentsize = 0x2e; - public static final int e_shnum = 0x30; - public static final int e_shstrndx = 0x32; -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Phdr.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Phdr.java deleted file mode 100644 index 95e2c27b2..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Phdr.java +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -// AUTOMATICALLY GENERATED CODE. Regenerate with genstructs.sh. -package com.facebook.soloader; -public final class Elf32_Phdr { - public static final int p_type = 0x0; - public static final int p_offset = 0x4; - public static final int p_vaddr = 0x8; - public static final int p_paddr = 0xc; - public static final int p_filesz = 0x10; - public static final int p_memsz = 0x14; - public static final int p_flags = 0x18; - public static final int p_align = 0x1c; -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Shdr.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Shdr.java deleted file mode 100644 index 35fc8599c..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf32_Shdr.java +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -// AUTOMATICALLY GENERATED CODE. Regenerate with genstructs.sh. -package com.facebook.soloader; -public final class Elf32_Shdr { - public static final int sh_name = 0x0; - public static final int sh_type = 0x4; - public static final int sh_flags = 0x8; - public static final int sh_addr = 0xc; - public static final int sh_offset = 0x10; - public static final int sh_size = 0x14; - public static final int sh_link = 0x18; - public static final int sh_info = 0x1c; - public static final int sh_addralign = 0x20; - public static final int sh_entsize = 0x24; -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Dyn.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Dyn.java deleted file mode 100644 index 89f2ddbdf..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Dyn.java +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -// AUTOMATICALLY GENERATED CODE. Regenerate with genstructs.sh. -package com.facebook.soloader; -public final class Elf64_Dyn { - public static final int d_tag = 0x0; - public static final int d_un = 0x8; -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Ehdr.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Ehdr.java deleted file mode 100644 index 4f6fa44ce..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Ehdr.java +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -// AUTOMATICALLY GENERATED CODE. Regenerate with genstructs.sh. -package com.facebook.soloader; -public final class Elf64_Ehdr { - public static final int e_ident = 0x0; - public static final int e_type = 0x10; - public static final int e_machine = 0x12; - public static final int e_version = 0x14; - public static final int e_entry = 0x18; - public static final int e_phoff = 0x20; - public static final int e_shoff = 0x28; - public static final int e_flags = 0x30; - public static final int e_ehsize = 0x34; - public static final int e_phentsize = 0x36; - public static final int e_phnum = 0x38; - public static final int e_shentsize = 0x3a; - public static final int e_shnum = 0x3c; - public static final int e_shstrndx = 0x3e; -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Phdr.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Phdr.java deleted file mode 100644 index b6436cbcb..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Phdr.java +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -// AUTOMATICALLY GENERATED CODE. Regenerate with genstructs.sh. -package com.facebook.soloader; -public final class Elf64_Phdr { - public static final int p_type = 0x0; - public static final int p_flags = 0x4; - public static final int p_offset = 0x8; - public static final int p_vaddr = 0x10; - public static final int p_paddr = 0x18; - public static final int p_filesz = 0x20; - public static final int p_memsz = 0x28; - public static final int p_align = 0x30; -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Shdr.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Shdr.java deleted file mode 100644 index 36e8693d4..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/Elf64_Shdr.java +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -// AUTOMATICALLY GENERATED CODE. Regenerate with genstructs.sh. -package com.facebook.soloader; -public final class Elf64_Shdr { - public static final int sh_name = 0x0; - public static final int sh_type = 0x4; - public static final int sh_flags = 0x8; - public static final int sh_addr = 0x10; - public static final int sh_offset = 0x18; - public static final int sh_size = 0x20; - public static final int sh_link = 0x28; - public static final int sh_info = 0x2c; - public static final int sh_addralign = 0x30; - public static final int sh_entsize = 0x38; -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/ExoSoSource.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/ExoSoSource.java deleted file mode 100644 index 1520aa1c9..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/ExoSoSource.java +++ /dev/null @@ -1,177 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.soloader; - -import java.io.File; -import java.io.IOException; -import android.content.Context; - -import java.util.jar.JarFile; -import java.util.jar.JarEntry; - -import java.util.regex.Pattern; -import java.util.regex.Matcher; - -import android.os.Build; -import android.system.Os; -import android.system.ErrnoException; - -import java.util.HashMap; -import java.util.Map; -import java.util.Enumeration; - -import java.io.InputStream; -import java.io.FileOutputStream; -import java.io.FileInputStream; -import java.io.BufferedReader; -import java.io.FileReader; - -import android.util.Log; - -/** - * {@link SoSource} that retrieves libraries from an exopackage repository. - */ -public class ExoSoSource extends DirectorySoSource { - - private static final String TAG = SoLoader.TAG; - private static final boolean DEBUG = SoLoader.DEBUG; - - /** - * @param context Application context - */ - public ExoSoSource(Context context) throws IOException { - // - // Initialize a normal DirectorySoSource that will load from our extraction directory. At this - // point, the directory may be empty or contain obsolete libraries, but that's okay. - // - - super(SysUtil.createLibsDirectory(context), DirectorySoSource.RESOLVE_DEPENDENCIES); - - // - // Synchronize the contents of that directory with the library payload in our APK, deleting and - // extracting as needed. - // - - File libsDir = super.soDirectory; - - if (DEBUG) { - Log.v(TAG, "synchronizing log directory: " + libsDir); - } - - Map providedLibraries = findProvidedLibraries(context); - try (FileLocker lock = SysUtil.lockLibsDirectory(context)) { - // Delete files in libsDir that we don't provide or that are out of date. Forget about any - // libraries that are up-to-date already so we don't unpack them below. - File extantFiles[] = libsDir.listFiles(); - for (int i = 0; i < extantFiles.length; ++i) { - File extantFile = extantFiles[i]; - - if (DEBUG) { - Log.v(TAG, "considering libdir file: " + extantFile); - } - - String name = extantFile.getName(); - File sourceFile = providedLibraries.get(name); - boolean shouldDelete = - (sourceFile == null || - sourceFile.length() != extantFile.length() || - sourceFile.lastModified() != extantFile.lastModified()); - boolean upToDate = (sourceFile != null && !shouldDelete); - - if (shouldDelete) { - if (DEBUG) { - Log.v(TAG, "deleting obsolete or unexpected file: " + extantFile); - } - SysUtil.deleteOrThrow(extantFile); - } - - if (upToDate) { - if (DEBUG) { - Log.v(TAG, "found up-to-date library: " + extantFile); - } - providedLibraries.remove(name); - } - } - - // Now extract any libraries left in providedLibraries; we removed all the up-to-date ones. - for (String soName : providedLibraries.keySet()) { - File sourceFile = providedLibraries.get(soName); - try (InputStream is = new FileInputStream(sourceFile)) { - if (DEBUG) { - Log.v(TAG, "extracting library: " + soName); - } - SysUtil.reliablyCopyExecutable( - is, - new File(libsDir, soName), - sourceFile.length(), - sourceFile.lastModified()); - } - - SysUtil.freeCopyBuffer(); - } - } - } - - /** - * Find the shared libraries provided through the exopackage directory and supported on this - * system. Each returend SoInfo points to the most preferred version of that library included in - * our exopackage directory: for example, if we're on an armv7-a system and we have both arm and - * armv7-a versions of libfoo, the returned entry for libfoo points to the armv7-a version of - * libfoo. - * - * The caller owns the returned value and may mutate it. - * - * @param context Application context - * @return Map of sonames to providing files - */ - private static Map findProvidedLibraries(Context context) throws IOException { - File exoDir = new File( - "/data/local/tmp/exopackage/" - + context.getPackageName() - + "/native-libs/"); - - HashMap providedLibraries = new HashMap<>(); - for (String abi : SysUtil.getSupportedAbis()) { - File abiDir = new File(exoDir, abi); - if (!abiDir.isDirectory()) { - continue; - } - - File metadata = new File(abiDir, "metadata.txt"); - if (!metadata.isFile()) { - continue; - } - - try (FileReader fr = new FileReader(metadata); - BufferedReader br = new BufferedReader(fr)) { - String line; - while ((line = br.readLine()) != null) { - if (line.length() == 0) { - continue; - } - - int sep = line.indexOf(' '); - if (sep == -1) { - throw new RuntimeException("illegal line in exopackage metadata: [" + line + "]"); - } - - String soName = line.substring(0, sep) + ".so"; - String backingFile = line.substring(sep + 1); - - if (!providedLibraries.containsKey(soName)) { - providedLibraries.put(soName, new File(abiDir, backingFile)); - } - } - } - } - - return providedLibraries; - } -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/FileLocker.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/FileLocker.java deleted file mode 100644 index 96a11f994..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/FileLocker.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.soloader; -import java.io.FileOutputStream; -import java.io.File; -import java.io.IOException; -import java.nio.channels.FileLock; -import java.io.Closeable; - -public final class FileLocker implements Closeable { - - private final FileOutputStream mLockFileOutputStream; - private final FileLock mLock; - - public static FileLocker lock(File lockFile) throws IOException { - return new FileLocker(lockFile); - } - - private FileLocker(File lockFile) throws IOException { - mLockFileOutputStream = new FileOutputStream(lockFile); - FileLock lock = null; - try { - lock = mLockFileOutputStream.getChannel().lock(); - } finally { - if (lock == null) { - mLockFileOutputStream.close(); - } - } - - mLock = lock; - } - - @Override - public void close() throws IOException { - try { - mLock.release(); - } finally { - mLockFileOutputStream.close(); - } - } -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/MinElf.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/MinElf.java deleted file mode 100644 index 0477ad71d..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/MinElf.java +++ /dev/null @@ -1,282 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.soloader; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.File; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.FileChannel; - -/** - * Extract SoLoader boottsrap information from an ELF file. This is not a general purpose ELF - * library. - * - * See specification at http://www.sco.com/developers/gabi/latest/contents.html. You will not be - * able to verify the operation of the functions below without having read the ELF specification. - */ -public final class MinElf { - - public static final int ELF_MAGIC = 0x464c457f; - - public static final int DT_NULL = 0; - public static final int DT_NEEDED = 1; - public static final int DT_STRTAB = 5; - - public static final int PT_LOAD = 1; - public static final int PT_DYNAMIC = 2; - - public static final int PN_XNUM = 0xFFFF; - - public static String[] extract_DT_NEEDED(File elfFile) throws IOException { - FileInputStream is = new FileInputStream(elfFile); - try { - return extract_DT_NEEDED(is.getChannel()); - } finally { - is.close(); // Won't throw - } - } - - /** - * Treating {@code bb} as an ELF file, extract all the DT_NEEDED entries from its dynamic section. - * - * @param fc FileChannel referring to ELF file - * @return Array of strings, one for each DT_NEEDED entry, in file order - */ - public static String[] extract_DT_NEEDED(FileChannel fc) - throws IOException { - - // - // All constants below are fixed by the ELF specification and are the offsets of fields within - // the elf.h data structures. - // - - ByteBuffer bb = ByteBuffer.allocate(8 /* largest read unit */); - - // Read ELF header. - - bb.order(ByteOrder.LITTLE_ENDIAN); - if (getu32(fc, bb, Elf32_Ehdr.e_ident) != ELF_MAGIC) { - throw new ElfError("file is not ELF"); - } - - boolean is32 = (getu8(fc, bb, Elf32_Ehdr.e_ident + 0x4) == 1); - if (getu8(fc, bb, Elf32_Ehdr.e_ident + 0x5) == 2) { - bb.order(ByteOrder.BIG_ENDIAN); - } - - // Offsets above are identical in 32- and 64-bit cases. - - // Find the offset of the dynamic linking information. - - long e_phoff = is32 - ? getu32(fc, bb, Elf32_Ehdr.e_phoff) - : get64(fc, bb, Elf64_Ehdr.e_phoff); - - long e_phnum = is32 - ? getu16(fc, bb, Elf32_Ehdr.e_phnum) - : getu16(fc, bb, Elf64_Ehdr.e_phnum); - - int e_phentsize = is32 - ? getu16(fc, bb, Elf32_Ehdr.e_phentsize) - : getu16(fc, bb, Elf64_Ehdr.e_phentsize); - - if (e_phnum == PN_XNUM) { // Overflowed into section[0].sh_info - - long e_shoff = is32 - ? getu32(fc, bb, Elf32_Ehdr.e_shoff) - : get64(fc, bb, Elf64_Ehdr.e_shoff); - - long sh_info = is32 - ? getu32(fc, bb, e_shoff + Elf32_Shdr.sh_info) - : getu32(fc, bb, e_shoff + Elf64_Shdr.sh_info); - - e_phnum = sh_info; - } - - long dynStart = 0; - long phdr = e_phoff; - - for (long i = 0; i < e_phnum; ++i) { - long p_type = is32 - ? getu32(fc, bb, phdr + Elf32_Phdr.p_type) - : getu32(fc, bb, phdr + Elf64_Phdr.p_type); - - if (p_type == PT_DYNAMIC) { - long p_offset = is32 - ? getu32(fc, bb, phdr + Elf32_Phdr.p_offset) - : get64(fc, bb, phdr + Elf64_Phdr.p_offset); - - dynStart = p_offset; - break; - } - - phdr += e_phentsize; - } - - if (dynStart == 0) { - throw new ElfError("ELF file does not contain dynamic linking information"); - } - - // Walk the items in the dynamic section, counting the DT_NEEDED entries. Also remember where - // the string table for those entries lives. That table is a pointer, which we translate to an - // offset below. - - long d_tag; - int nr_DT_NEEDED = 0; - long dyn = dynStart; - long ptr_DT_STRTAB = 0; - - do { - d_tag = is32 - ? getu32(fc, bb, dyn + Elf32_Dyn.d_tag) - : get64(fc, bb, dyn + Elf64_Dyn.d_tag); - - if (d_tag == DT_NEEDED) { - if (nr_DT_NEEDED == Integer.MAX_VALUE) { - throw new ElfError("malformed DT_NEEDED section"); - } - - nr_DT_NEEDED += 1; - } else if (d_tag == DT_STRTAB) { - ptr_DT_STRTAB = is32 - ? getu32(fc, bb, dyn + Elf32_Dyn.d_un) - : get64(fc, bb, dyn + Elf64_Dyn.d_un); - } - - dyn += is32 ? 8 : 16; - } while (d_tag != DT_NULL); - - if (ptr_DT_STRTAB == 0) { - throw new ElfError("Dynamic section string-table not found"); - } - - // Translate the runtime string table pointer we found above to a file offset. - - long off_DT_STRTAB = 0; - phdr = e_phoff; - - for (int i = 0; i < e_phnum; ++i) { - long p_type = is32 - ? getu32(fc, bb, phdr + Elf32_Phdr.p_type) - : getu32(fc, bb, phdr + Elf64_Phdr.p_type); - - if (p_type == PT_LOAD) { - long p_vaddr = is32 - ? getu32(fc, bb, phdr + Elf32_Phdr.p_vaddr) - : get64(fc, bb, phdr + Elf64_Phdr.p_vaddr); - - long p_memsz = is32 - ? getu32(fc, bb, phdr + Elf32_Phdr.p_memsz) - : get64(fc, bb, phdr + Elf64_Phdr.p_memsz); - - if (p_vaddr <= ptr_DT_STRTAB && ptr_DT_STRTAB < p_vaddr + p_memsz) { - long p_offset = is32 - ? getu32(fc, bb, phdr + Elf32_Phdr.p_offset) - : get64(fc, bb, phdr + Elf64_Phdr.p_offset); - - off_DT_STRTAB = p_offset + (ptr_DT_STRTAB - p_vaddr); - break; - } - } - - phdr += e_phentsize; - } - - if (off_DT_STRTAB == 0) { - throw new ElfError("did not find file offset of DT_STRTAB table"); - } - - String[] needed = new String[nr_DT_NEEDED]; - - nr_DT_NEEDED = 0; - dyn = dynStart; - - do { - d_tag = is32 - ? getu32(fc, bb, dyn + Elf32_Dyn.d_tag) - : get64(fc, bb, dyn + Elf64_Dyn.d_tag); - - if (d_tag == DT_NEEDED) { - long d_val = is32 - ? getu32(fc, bb, dyn + Elf32_Dyn.d_un) - : get64(fc, bb, dyn + Elf64_Dyn.d_un); - - needed[nr_DT_NEEDED] = getSz(fc, bb, off_DT_STRTAB + d_val); - if (nr_DT_NEEDED == Integer.MAX_VALUE) { - throw new ElfError("malformed DT_NEEDED section"); - } - - nr_DT_NEEDED += 1; - } - - dyn += is32 ? 8 : 16; - } while (d_tag != DT_NULL); - - if (nr_DT_NEEDED != needed.length) { - throw new ElfError("malformed DT_NEEDED section"); - } - - return needed; - } - - private static String getSz(FileChannel fc, ByteBuffer bb, long offset) - throws IOException { - StringBuilder sb = new StringBuilder(); - short b; - while ((b = getu8(fc, bb, offset++)) != 0) { - sb.append((char) b); - } - - return sb.toString(); - } - - private static void read(FileChannel fc, ByteBuffer bb, int sz, long offset) - throws IOException { - bb.position(0); - bb.limit(sz); - if (fc.read(bb, offset) != sz) { - throw new ElfError("ELF file truncated"); - } - - bb.position(0); - } - - private static long get64(FileChannel fc, ByteBuffer bb, long offset) - throws IOException { - read(fc, bb, 8, offset); - return bb.getLong(); - } - - private static long getu32(FileChannel fc, ByteBuffer bb, long offset) - throws IOException { - read(fc, bb, 4, offset); - return bb.getInt() & 0xFFFFFFFFL; // signed -> unsigned - } - - private static int getu16(FileChannel fc, ByteBuffer bb, long offset) - throws IOException { - read(fc, bb, 2, offset); - return bb.getShort() & (int) 0xFFFF; // signed -> unsigned - } - - private static short getu8(FileChannel fc, ByteBuffer bb, long offset) - throws IOException { - read(fc, bb, 1, offset); - return (short) (bb.get() & 0xFF); // signed -> unsigned - } - - private static class ElfError extends RuntimeException { - ElfError(String why) { - super(why); - } - } -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/NativeLibrary.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/NativeLibrary.java deleted file mode 100644 index 7277474d6..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/NativeLibrary.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.soloader; - -import java.util.List; - -import android.util.Log; - -/** - * This is the base class for all the classes representing certain native library. - * For loading native libraries we should always inherit from this class and provide relevant - * information (libraries to load, code to test native call, dependencies?). - *

- * This instances should be singletons provided by DI. - *

- * This is a basic template but could be improved if we find the need. - */ -public abstract class NativeLibrary { - private static final String TAG = NativeLibrary.class.getName(); - - private final Object mLock; - private List mLibraryNames; - private Boolean mLoadLibraries; - private boolean mLibrariesLoaded; - private volatile UnsatisfiedLinkError mLinkError; - - protected NativeLibrary(List libraryNames) { - mLock = new Object(); - mLoadLibraries = true; - mLibrariesLoaded = false; - mLinkError = null; - mLibraryNames = libraryNames; - } - - /** - * safe loading of native libs - * @return true if native libs loaded properly, false otherwise - */ - public boolean loadLibraries() { - synchronized (mLock) { - if (mLoadLibraries == false) { - return mLibrariesLoaded; - } - try { - for (String name: mLibraryNames) { - SoLoader.loadLibrary(name); - } - initialNativeCheck(); - mLibrariesLoaded = true; - mLibraryNames = null; - } catch (UnsatisfiedLinkError error) { - Log.e(TAG, "Failed to load native lib: ", error); - mLinkError = error; - mLibrariesLoaded = false; - } - mLoadLibraries = false; - return mLibrariesLoaded; - } - } - - /** - * loads libraries (if not loaded yet), throws on failure - * @throws UnsatisfiedLinkError - */ - - public void ensureLoaded() throws UnsatisfiedLinkError { - if (!loadLibraries()) { - throw mLinkError; - } - } - - /** - * Override this method to make some concrete (quick and harmless) native call. - * This avoids lazy-loading some phones (LG) use when we call loadLibrary. If there's a problem - * we'll face an UnsupportedLinkError when first using the feature instead of here. - * This check force a check right when intended. - * This way clients of this library can know if it's loaded for sure or not. - * @throws UnsatisfiedLinkError if there was an error loading native library - */ - protected void initialNativeCheck() throws UnsatisfiedLinkError { - } - - public UnsatisfiedLinkError getError() { - return mLinkError; - } -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/NoopSoSource.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/NoopSoSource.java deleted file mode 100644 index cd5d15e48..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/NoopSoSource.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.soloader; - -import java.io.File; - -/** - * {@link SoSource} that does nothing and pretends to successfully load all libraries. - */ -public class NoopSoSource extends SoSource { - @Override - public int loadLibrary(String soName, int loadFlags) { - return LOAD_RESULT_LOADED; - } - - @Override - public File unpackLibrary(String soName) { - throw new UnsupportedOperationException( - "unpacking not supported in test mode"); - } -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SoLoader.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SoLoader.java deleted file mode 100644 index a070ed9a9..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SoLoader.java +++ /dev/null @@ -1,237 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.soloader; - -import java.io.BufferedOutputStream; -import java.io.Closeable; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.HashSet; -import java.util.ArrayList; -import java.io.FileNotFoundException; - -import java.util.Set; - -import javax.annotation.Nullable; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.os.Build; -import android.os.StatFs; -import android.util.Log; - -import android.content.pm.ApplicationInfo; - -/** - * Note that {@link com.facebook.base.app.DelegatingApplication} will automatically register itself - * with SoLoader before running application-specific code; most applications do not need to call - * {@link #init} explicitly. - */ -@SuppressLint({ - "BadMethodUse-android.util.Log.v", - "BadMethodUse-android.util.Log.d", - "BadMethodUse-android.util.Log.i", - "BadMethodUse-android.util.Log.w", - "BadMethodUse-android.util.Log.e", -}) -public class SoLoader { - - /* package */ static final String TAG = "SoLoader"; - /* package */ static final boolean DEBUG = false; - - /** - * Ordered list of sources to consult when trying to load a shared library or one of its - * dependencies. {@code null} indicates that SoLoader is uninitialized. - */ - @Nullable private static SoSource[] sSoSources = null; - - /** - * Records the sonames (e.g., "libdistract.so") of shared libraries we've loaded. - */ - private static final Set sLoadedLibraries = new HashSet<>(); - - /** - * Initializes native code loading for this app; this class's other static facilities cannot be - * used until this {@link #init} is called. This method is idempotent: calls after the first are - * ignored. - * - * @param context - application context. - * @param isNativeExopackageEnabled - whether native exopackage feature is enabled in the build. - */ - public static synchronized void init(@Nullable Context context, boolean isNativeExopackageEnabled) { - if (sSoSources == null) { - ArrayList soSources = new ArrayList<>(); - - // - // Add SoSource objects for each of the system library directories. - // - - String LD_LIBRARY_PATH = System.getenv("LD_LIBRARY_PATH"); - if (LD_LIBRARY_PATH == null) { - LD_LIBRARY_PATH = "/vendor/lib:/system/lib"; - } - - String[] systemLibraryDirectories = LD_LIBRARY_PATH.split(":"); - for (int i = 0; i < systemLibraryDirectories.length; ++i) { - // Don't pass DirectorySoSource.RESOLVE_DEPENDENCIES for directories we find on - // LD_LIBRARY_PATH: Bionic's dynamic linker is capable of correctly resolving dependencies - // these libraries have on each other, so doing that ourselves would be a waste. - File systemSoDirectory = new File(systemLibraryDirectories[i]); - soSources.add( - new DirectorySoSource( - systemSoDirectory, - DirectorySoSource.ON_LD_LIBRARY_PATH)); - } - - // - // We can only proceed forward if we have a Context. The prominent case - // where we don't have a Context is barebones dalvikvm instantiations. In - // that case, the caller is responsible for providing a correct LD_LIBRARY_PATH. - // - - if (context != null) { - // - // Prepend our own SoSource for our own DSOs. - // - - ApplicationInfo applicationInfo = context.getApplicationInfo(); - boolean isSystemApplication = - (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 && - (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 0; - - try { - if (isNativeExopackageEnabled) { - soSources.add(0, new ExoSoSource(context)); - } else if (isSystemApplication) { - soSources.add(0, new ApkSoSource(context)); - } else { - // Delete the old libs directory if we don't need it. - SysUtil.dumbDeleteRecrusive(SysUtil.getLibsDirectory(context)); - - int ourSoSourceFlags = 0; - - // On old versions of Android, Bionic doesn't add our library directory to its internal - // search path, and the system doesn't resolve dependencies between modules we ship. On - // these systems, we resolve dependencies ourselves. On other systems, Bionic's built-in - // resolver suffices. - - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR1) { - ourSoSourceFlags |= DirectorySoSource.RESOLVE_DEPENDENCIES; - } - - SoSource ourSoSource = new DirectorySoSource( - new File(applicationInfo.nativeLibraryDir), - ourSoSourceFlags); - - soSources.add(0, ourSoSource); - } - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - sSoSources = soSources.toArray(new SoSource[soSources.size()]); - } - } - - /** - * Turn shared-library loading into a no-op. Useful in special circumstances. - */ - public static void setInTestMode() { - sSoSources = new SoSource[]{new NoopSoSource()}; - } - - /** - * Load a shared library, initializing any JNI binding it contains. - * - * @param shortName Name of library to find, without "lib" prefix or ".so" suffix - */ - public static synchronized void loadLibrary(String shortName) - throws UnsatisfiedLinkError - { - if (sSoSources == null) { - // This should never happen during normal operation, - // but if we're running in a non-Android environment, - // fall back to System.loadLibrary. - if ("http://www.android.com/".equals(System.getProperty("java.vendor.url"))) { - // This will throw. - assertInitialized(); - } else { - // Not on an Android system. Ask the JVM to load for us. - System.loadLibrary(shortName); - return; - } - } - - try { - loadLibraryBySoName(System.mapLibraryName(shortName), 0); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - /** - * Unpack library and its dependencies, returning the location of the unpacked library file. All - * non-system dependencies of the given library will either be on LD_LIBRARY_PATH or will be in - * the same directory as the returned File. - * - * @param shortName Name of library to find, without "lib" prefix or ".so" suffix - * @return Unpacked DSO location - */ - public static File unpackLibraryAndDependencies(String shortName) - throws UnsatisfiedLinkError - { - assertInitialized(); - try { - return unpackLibraryBySoName(System.mapLibraryName(shortName)); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - /* package */ static void loadLibraryBySoName(String soName, int loadFlags) throws IOException { - int result = sLoadedLibraries.contains(soName) - ? SoSource.LOAD_RESULT_LOADED - : SoSource.LOAD_RESULT_NOT_FOUND; - - for (int i = 0; result == SoSource.LOAD_RESULT_NOT_FOUND && i < sSoSources.length; ++i) { - result = sSoSources[i].loadLibrary(soName, loadFlags); - } - - if (result == SoSource.LOAD_RESULT_NOT_FOUND) { - throw new UnsatisfiedLinkError("could find DSO to load: " + soName); - } - - if (result == SoSource.LOAD_RESULT_LOADED) { - sLoadedLibraries.add(soName); - } - } - - /* package */ static File unpackLibraryBySoName(String soName) throws IOException { - for (int i = 0; i < sSoSources.length; ++i) { - File unpacked = sSoSources[i].unpackLibrary(soName); - if (unpacked != null) { - return unpacked; - } - } - - throw new FileNotFoundException(soName); - } - - private static void assertInitialized() { - if (sSoSources == null) { - throw new RuntimeException("SoLoader.init() not yet called"); - } - } -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SoSource.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SoSource.java deleted file mode 100644 index 016013e15..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SoSource.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.soloader; - -import java.io.File; -import java.io.IOException; - -abstract public class SoSource { - - /** - * This SoSource doesn't know how to provide the given library. - */ - public static final int LOAD_RESULT_NOT_FOUND = 0; - - /** - * This SoSource loaded the given library. - */ - public static final int LOAD_RESULT_LOADED = 1; - - /** - * This SoSource did not load the library, but verified that the system loader will load it if - * some other library depends on it. Returned only if LOAD_FLAG_ALLOW_IMPLICIT_PROVISION is - * provided to loadLibrary. - */ - public static final int LOAD_RESULT_IMPLICITLY_PROVIDED = 2; - - /** - * Allow loadLibrary to implicitly provide the library instead of actually loading it. - */ - public static final int LOAD_FLAG_ALLOW_IMPLICIT_PROVISION = 1; - - /** - * Load a shared library library into this process. This routine is independent of - * {@link #loadLibrary}. - * - * @param soName Name of library to load - * @param loadFlags Zero or more of the LOAD_FLAG_XXX constants. - * @return One of the LOAD_RESULT_XXX constants. - */ - abstract public int loadLibrary(String soName, int LoadFlags) throws IOException; - - /** - * Ensure that a shared library exists on disk somewhere. This routine is independent of - * {@link #loadLibrary}. - * - * @param soName Name of library to load - * @return File if library found; {@code null} if not. - */ - abstract public File unpackLibrary(String soName) throws IOException; -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SysUtil.java b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SysUtil.java deleted file mode 100644 index 91f28583e..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/SysUtil.java +++ /dev/null @@ -1,205 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.soloader; - -import java.io.File; -import java.io.IOException; -import android.content.Context; - -import java.util.jar.JarFile; -import java.util.jar.JarEntry; - -import java.util.regex.Pattern; -import java.util.regex.Matcher; - -import android.os.Build; -import android.system.Os; -import android.system.ErrnoException; - -import java.util.HashMap; -import java.util.Map; -import java.util.Enumeration; - -import java.io.InputStream; -import java.io.FileOutputStream; -import java.io.FileDescriptor; - -/*package*/ final class SysUtil { - - private static byte[] cachedBuffer = null; - - /** - * Copy from an inputstream to a named filesystem file. Take care to ensure that we can detect - * incomplete copies and that the copied bytes make it to stable storage before returning. - * The destination file will be marked executable. - * - * This routine caches an internal buffer between invocations; after making a sequence of calls - * {@link #reliablyCopyExecutable} calls, call {@link #freeCopyBuffer} to release this buffer. - * - * @param is Stream from which to copy - * @param destination File to which to write - * @param expectedSize Number of bytes we expect to write; -1 if unknown - * @param time Modification time to which to set file on success; must be in the past - */ - public static void reliablyCopyExecutable( - InputStream is, - File destination, - long expectedSize, - long time) throws IOException { - destination.delete(); - try (FileOutputStream os = new FileOutputStream(destination)) { - byte buffer[]; - if (cachedBuffer == null) { - cachedBuffer = buffer = new byte[16384]; - } else { - buffer = cachedBuffer; - } - - int nrBytes; - if (expectedSize > 0) { - fallocateIfSupported(os.getFD(), expectedSize); - } - - while ((nrBytes = is.read(buffer, 0, buffer.length)) >= 0) { - os.write(buffer, 0, nrBytes); - } - - os.getFD().sync(); - destination.setExecutable(true); - destination.setLastModified(time); - os.getFD().sync(); - } - } - - /** - * Free the internal buffer cache for {@link #reliablyCopyExecutable}. - */ - public static void freeCopyBuffer() { - cachedBuffer = null; - } - - /** - * Determine how preferred a given ABI is on this system. - * - * @param supportedAbis ABIs on this system - * @param abi ABI of a shared library we might want to unpack - * @return -1 if not supported or an integer, smaller being more preferred - */ - public static int findAbiScore(String[] supportedAbis, String abi) { - for (int i = 0; i < supportedAbis.length; ++i) { - if (supportedAbis[i] != null && abi.equals(supportedAbis[i])) { - return i; - } - } - - return -1; - } - - public static void deleteOrThrow(File file) throws IOException { - if (!file.delete()) { - throw new IOException("could not delete file " + file); - } - } - - /** - * Return an list of ABIs we supported on this device ordered according to preference. Use a - * separate inner class to isolate the version-dependent call where it won't cause the whole - * class to fail preverification. - * - * @return Ordered array of supported ABIs - */ - public static String[] getSupportedAbis() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return new String[]{Build.CPU_ABI, Build.CPU_ABI2}; - } else { - return LollipopSysdeps.getSupportedAbis(); - } - } - - /** - * Pre-allocate disk space for a file if we can do that - * on this version of the OS. - * - * @param fd File descriptor for file - * @param length Number of bytes to allocate. - */ - public static void fallocateIfSupported(FileDescriptor fd, long length) throws IOException { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - LollipopSysdeps.fallocate(fd, length); - } - } - - public static FileLocker lockLibsDirectory(Context context) throws IOException { - File lockFile = new File(context.getApplicationInfo().dataDir, "libs-dir-lock"); - return FileLocker.lock(lockFile); - } - - /** - * Return the directory into which we put our self-extracted native libraries. - * - * @param context Application context - * @return File pointing to an existing directory - */ - /* package */ static File getLibsDirectory(Context context) { - return new File(context.getApplicationInfo().dataDir, "app_libs"); - } - - /** - * Return the directory into which we put our self-extracted native libraries and make sure it - * exists. - */ - /* package */ static File createLibsDirectory(Context context) { - File libsDirectory = getLibsDirectory(context); - if (!libsDirectory.isDirectory() && !libsDirectory.mkdirs()) { - throw new RuntimeException("could not create libs directory"); - } - - return libsDirectory; - } - - /** - * Delete a directory and its contents. - * - * WARNING: Java APIs do not let us distinguish directories from symbolic links to directories. - * Consequently, if the directory contains symbolic links to directories, we will attempt to - * delete the contents of pointed-to directories. - * - * @param file File or directory to delete - */ - /* package */ static void dumbDeleteRecrusive(File file) throws IOException { - if (file.isDirectory()) { - for (File entry : file.listFiles()) { - dumbDeleteRecrusive(entry); - } - } - - if (!file.delete() && file.exists()) { - throw new IOException("could not delete: " + file); - } - } - - /** - * Encapsulate Lollipop-specific calls into an independent class so we don't fail preverification - * downlevel. - */ - private static final class LollipopSysdeps { - public static String[] getSupportedAbis() { - return Build.SUPPORTED_32_BIT_ABIS; // We ain't doing no newfangled 64-bit - } - - public static void fallocate(FileDescriptor fd, long length) throws IOException { - try { - Os.posix_fallocate(fd, 0, length); - } catch (ErrnoException ex) { - throw new IOException(ex.toString(), ex); - } - } - } -} diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/genstructs.sh b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/genstructs.sh deleted file mode 100644 index a7bcd49a5..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/genstructs.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -# -# This script generates Java structures that contain the offsets of -# fields in various ELF ABI structures. com.facebook.soloader.MinElf -# uses these structures while parsing ELF files. -# - -set -euo pipefail - -struct2java() { - ../../../../scripts/struct2java.py "$@" -} - -declare -a structs=(Elf32_Ehdr Elf64_Ehdr) -structs+=(Elf32_Ehdr Elf64_Ehdr) -structs+=(Elf32_Phdr Elf64_Phdr) -structs+=(Elf32_Shdr Elf64_Shdr) -structs+=(Elf32_Dyn Elf64_Dyn) - -for struct in "${structs[@]}"; do - cat > elfhdr.c < -static const $struct a; -EOF - gcc -g -c -o elfhdr.o elfhdr.c - cat > $struct.java <> $struct.java -done - -rm -f elfhdr.o elfhdr.c diff --git a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/soloader.pro b/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/soloader.pro deleted file mode 100644 index 4a832314c..000000000 --- a/ReactAndroid/src/main/libraries/soloader/java/com/facebook/soloader/soloader.pro +++ /dev/null @@ -1,6 +0,0 @@ -# Ensure that methods from LollipopSysdeps don't get inlined. LollipopSysdeps.fallocate references -# an exception that isn't present prior to Lollipop, which trips up the verifier if the class is -# loaded on a pre-Lollipop OS. --keep class com.facebook.soloader.SysUtil$LollipopSysdeps { - public ; -}